2
0

heap.inc 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  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. {*****************************************************************************
  462. SysGetMem
  463. *****************************************************************************}
  464. function SysGetMem(size : longint):pointer;
  465. type
  466. heaperrorproc=function(size:longint):integer;
  467. var
  468. proc : heaperrorproc;
  469. pcurr : pfreerecord;
  470. again : boolean;
  471. s,s1,i,
  472. sizeleft : longint;
  473. {$ifdef BESTMATCH}
  474. pbest : pfreerecord;
  475. {$endif}
  476. begin
  477. { Something to allocate ? }
  478. if size<=0 then
  479. begin
  480. { give an error for < 0 }
  481. if size<0 then
  482. HandleError(204);
  483. { we always need to allocate something, using heapend is not possible,
  484. because heappend can be changed by growheap (PFV) }
  485. size:=1;
  486. end;
  487. { calc to multiply of 16 after adding the needed 8 bytes heaprecord }
  488. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  489. dec(internal_memavail,size);
  490. { try to find a block in one of the freelists per size }
  491. s:=size shr blockshr;
  492. if s<=maxblock then
  493. begin
  494. pcurr:=freelists[s];
  495. { correct size match ? }
  496. if assigned(pcurr) then
  497. begin
  498. { create the block we should return }
  499. sysgetmem:=pointer(pcurr)+sizeof(theaprecord);
  500. { fix size }
  501. pcurr^.size:=pcurr^.size or usedmask;
  502. { update freelist }
  503. freelists[s]:=pcurr^.next;
  504. {$ifdef SYSTEMDEBUG}
  505. dec(freecount[s]);
  506. {$endif SYSTEMDEBUG}
  507. if assigned(freelists[s]) then
  508. freelists[s]^.prev:=nil;
  509. {$ifdef TestFreeLists}
  510. if test_each then
  511. TestFreeLists;
  512. {$endif TestFreeLists}
  513. exit;
  514. end;
  515. {$ifdef SMALLATHEAPPTR}
  516. if heapend-heapptr>=size then
  517. begin
  518. sysgetmem:=heapptr;
  519. { set end flag if we do not have enough room to add
  520. another tfreerecord behind }
  521. if (heapptr+size+sizeof(tfreerecord)>=heapend) then
  522. pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
  523. else
  524. pheaprecord(sysgetmem)^.size:=size or usedmask;
  525. inc(sysgetmem,sizeof(theaprecord));
  526. inc(heapptr,size);
  527. {$ifdef TestFreeLists}
  528. if test_each then
  529. TestFreeLists;
  530. {$endif TestFreeLists}
  531. exit;
  532. end;
  533. {$endif}
  534. {$ifdef REUSEBIGGER}
  535. { try a bigger block }
  536. s1:=s+s;
  537. i:=0;
  538. while (s1<=maxblock) and (i<maxreusebigger) do
  539. begin
  540. pcurr:=freelists[s1];
  541. if assigned(pcurr) then
  542. begin
  543. s:=s1;
  544. break;
  545. end;
  546. inc(s1);
  547. inc(i);
  548. end;
  549. {$endif}
  550. end
  551. else
  552. pcurr:=nil;
  553. { not found, then check the main freelist for the first match }
  554. if not(assigned(pcurr)) then
  555. begin
  556. s:=0;
  557. {$ifdef BESTMATCH}
  558. pbest:=nil;
  559. {$endif}
  560. pcurr:=freelists[0];
  561. while assigned(pcurr) do
  562. begin
  563. {$ifdef BESTMATCH}
  564. if pcurr^.size=size then
  565. break
  566. else
  567. begin
  568. if (pcurr^.size>size) then
  569. begin
  570. if (not assigned(pbest)) or
  571. (pcurr^.size<pbest^.size) then
  572. pbest:=pcurr;
  573. end;
  574. end;
  575. {$else}
  576. if pcurr^.size>=size then
  577. break;
  578. {$endif}
  579. pcurr:=pcurr^.next;
  580. end;
  581. {$ifdef BESTMATCH}
  582. if not assigned(pcurr) then
  583. pcurr:=pbest;
  584. {$endif}
  585. end;
  586. { have we found a block, then get it and free up the other left part,
  587. if no blocks are found then allocated at the heapptr or grow the heap }
  588. if assigned(pcurr) then
  589. begin
  590. { get pointer of the block we should return }
  591. sysgetmem:=pointer(pcurr);
  592. { remove the current block from the freelist }
  593. if assigned(pcurr^.next) then
  594. pcurr^.next^.prev:=pcurr^.prev;
  595. if assigned(pcurr^.prev) then
  596. pcurr^.prev^.next:=pcurr^.next
  597. else
  598. freelists[s]:=pcurr^.next;
  599. {$ifdef SYSTEMDEBUG}
  600. dec(freecount[s]);
  601. {$endif SYSTEMDEBUG}
  602. { create the left over freelist block, if at least 16 bytes are free }
  603. sizeleft:=pcurr^.size-size;
  604. if sizeleft>=sizeof(tfreerecord) then
  605. begin
  606. pcurr:=pfreerecord(pointer(pcurr)+size);
  607. { inherit the beforeheapendmask }
  608. pcurr^.size:=sizeleft or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
  609. { insert the block in the freelist }
  610. pcurr^.prev:=nil;
  611. s1:=sizeleft shr blockshr;
  612. if s1>maxblock then
  613. s1:=0;
  614. pcurr^.next:=freelists[s1];
  615. if assigned(freelists[s1]) then
  616. freelists[s1]^.prev:=pcurr;
  617. freelists[s1]:=pcurr;
  618. {$ifdef SYSTEMDEBUG}
  619. inc(freecount[s1]);
  620. {$endif SYSTEMDEBUG}
  621. { create the block we need to return }
  622. pheaprecord(sysgetmem)^.size:=size or usedmask;
  623. end
  624. else
  625. begin
  626. { create the block we need to return }
  627. pheaprecord(sysgetmem)^.size:=size or usedmask or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
  628. end;
  629. inc(sysgetmem,sizeof(theaprecord));
  630. {$ifdef TestFreeLists}
  631. if test_each then
  632. TestFreeLists;
  633. {$endif TestFreeLists}
  634. exit;
  635. end;
  636. { Lastly, the top of the heap is checked, to see if there is }
  637. { still memory available. }
  638. repeat
  639. again:=false;
  640. if heapend-heapptr>=size then
  641. begin
  642. sysgetmem:=heapptr;
  643. if (heapptr+size+sizeof(tfreerecord)>=heapend) then
  644. pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
  645. else
  646. pheaprecord(sysgetmem)^.size:=size or usedmask;
  647. inc(sysgetmem,sizeof(theaprecord));
  648. inc(heapptr,size);
  649. {$ifdef TestFreeLists}
  650. if test_each then
  651. TestFreeLists;
  652. {$endif TestFreeLists}
  653. exit;
  654. end;
  655. { Call the heaperror proc }
  656. if assigned(heaperror) then
  657. begin
  658. proc:=heaperrorproc(heaperror);
  659. case proc(size) of
  660. 0 : HandleError(203);
  661. 1 : sysgetmem:=nil;
  662. 2 : again:=true;
  663. end;
  664. end
  665. else
  666. HandleError(203);
  667. until not again;
  668. {$ifdef TestFreeLists}
  669. if test_each then
  670. TestFreeLists;
  671. {$endif TestFreeLists}
  672. end;
  673. {$ifdef CONCATFREE}
  674. {*****************************************************************************
  675. Try concat freerecords
  676. *****************************************************************************}
  677. procedure TryConcatFreeRecord(pcurr:pfreerecord);
  678. var
  679. hp : pfreerecord;
  680. pcurrsize,s1 : longint;
  681. begin
  682. pcurrsize:=pcurr^.size and sizemask;
  683. hp:=pcurr;
  684. repeat
  685. { block used or before a heapend ? }
  686. if (hp^.size and beforeheapendmask)<>0 then
  687. begin
  688. { Peter, why can't we add this one if free ?? }
  689. pcurr^.size:=pcurrsize or beforeheapendmask;
  690. pcurr^.next:=freelists[0];
  691. if assigned(pcurr^.next) then
  692. pcurr^.next^.prev:=pcurr;
  693. freelists[0]:=pcurr;
  694. {$ifdef SYSTEMDEBUG}
  695. inc(freecount[0]);
  696. {$endif SYSTEMDEBUG}
  697. break;
  698. end;
  699. { get next block }
  700. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  701. { when we're at heapptr then we can stop and set heapptr to pcurr }
  702. if (hp=heapptr) then
  703. begin
  704. heapptr:=pcurr;
  705. break;
  706. end;
  707. { block is used? then we stop and add the block to the freelist }
  708. if (hp^.size and usedmask)<>0 then
  709. begin
  710. pcurr^.size:=pcurrsize;
  711. pcurr^.next:=freelists[0];
  712. if assigned(pcurr^.next) then
  713. pcurr^.next^.prev:=pcurr;
  714. freelists[0]:=pcurr;
  715. {$ifdef SYSTEMDEBUG}
  716. inc(freecount[0]);
  717. {$endif SYSTEMDEBUG}
  718. break;
  719. end;
  720. { remove block from freelist and increase the size }
  721. s1:=hp^.size and sizemask;
  722. inc(pcurrsize,s1);
  723. s1:=s1 shr blockshr;
  724. if s1>maxblock then
  725. s1:=0;
  726. if assigned(hp^.next) then
  727. hp^.next^.prev:=hp^.prev;
  728. if assigned(hp^.prev) then
  729. hp^.prev^.next:=hp^.next
  730. else
  731. freelists[s1]:=hp^.next;
  732. {$ifdef SYSTEMDEBUG}
  733. dec(freecount[s1]);
  734. {$endif SYSTEMDEBUG}
  735. until false;
  736. end;
  737. {$endif CONCATFREE}
  738. {*****************************************************************************
  739. SysFreeMem
  740. *****************************************************************************}
  741. Function SysFreeMem(p : pointer):Longint;
  742. var
  743. pcurrsize,s : longint;
  744. pcurr : pfreerecord;
  745. begin
  746. if p=nil then
  747. HandleError(204);
  748. { fix p to point to the heaprecord }
  749. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  750. pcurrsize:=pcurr^.size and sizemask;
  751. inc(internal_memavail,pcurrsize);
  752. { insert the block in it's freelist }
  753. pcurr^.size:=pcurr^.size and (not usedmask);
  754. pcurr^.prev:=nil;
  755. s:=pcurrsize shr blockshr;
  756. if s>maxblock then
  757. {$ifdef CONCATFREE}
  758. TryConcatFreeRecord(pcurr)
  759. else
  760. {$else}
  761. s:=0;
  762. {$endif}
  763. begin
  764. pcurr^.next:=freelists[s];
  765. if assigned(pcurr^.next) then
  766. pcurr^.next^.prev:=pcurr;
  767. freelists[s]:=pcurr;
  768. {$ifdef SYSTEMDEBUG}
  769. inc(freecount[s]);
  770. {$endif SYSTEMDEBUG}
  771. end;
  772. SysFreeMem:=pcurrsize;
  773. {$ifdef TestFreeLists}
  774. if test_each then
  775. TestFreeLists;
  776. {$endif TestFreeLists}
  777. end;
  778. {*****************************************************************************
  779. SysFreeMemSize
  780. *****************************************************************************}
  781. Function SysFreeMemSize(p : pointer;size : longint):longint;
  782. var
  783. pcurrsize,s : longint;
  784. pcurr : pfreerecord;
  785. begin
  786. SysFreeMemSize:=0;
  787. if size<=0 then
  788. begin
  789. if size<0 then
  790. HandleError(204);
  791. exit;
  792. end;
  793. if p=nil then
  794. HandleError(204);
  795. { fix p to point to the heaprecord }
  796. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  797. pcurrsize:=pcurr^.size and sizemask;
  798. inc(internal_memavail,pcurrsize);
  799. { size check }
  800. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  801. if size<>pcurrsize then
  802. HandleError(204);
  803. { insert the block in it's freelist }
  804. pcurr^.size:=pcurr^.size and (not usedmask);
  805. pcurr^.prev:=nil;
  806. { set the return values }
  807. s:=pcurrsize shr blockshr;
  808. if s>maxblock then
  809. {$ifdef CONCATFREE}
  810. TryConcatFreeRecord(pcurr)
  811. else
  812. {$else}
  813. s:=0;
  814. {$endif}
  815. begin
  816. pcurr^.next:=freelists[s];
  817. if assigned(pcurr^.next) then
  818. pcurr^.next^.prev:=pcurr;
  819. freelists[s]:=pcurr;
  820. {$ifdef SYSTEMDEBUG}
  821. inc(freecount[s]);
  822. {$endif SYSTEMDEBUG}
  823. end;
  824. SysFreeMemSize:=pcurrsize;
  825. {$ifdef TestFreeLists}
  826. if test_each then
  827. TestFreeLists;
  828. {$endif TestFreeLists}
  829. end;
  830. {*****************************************************************************
  831. SysMemSize
  832. *****************************************************************************}
  833. function SysMemSize(p:pointer):longint;
  834. begin
  835. {$ifdef MT}
  836. try
  837. EnterCriticalSection(cs_systemheap);
  838. {$endif MT}
  839. SysMemSize:=(pheaprecord(pointer(p)-sizeof(theaprecord))^.size and sizemask)-sizeof(theaprecord);
  840. {$ifdef MT}
  841. finally
  842. LeaveCriticalSection(cs_systemheap);
  843. end;
  844. {$endif MT}
  845. end;
  846. {*****************************************************************************
  847. SysAllocMem
  848. *****************************************************************************}
  849. function SysAllocMem(size : longint):pointer;
  850. begin
  851. sysallocmem:=MemoryManager.GetMem(size);
  852. if sysallocmem<>nil then
  853. FillChar(sysallocmem^,size,0);
  854. end;
  855. {*****************************************************************************
  856. SysResizeMem
  857. *****************************************************************************}
  858. function SysTryResizeMem(var p:pointer;size : longint):boolean;
  859. var
  860. oldsize,
  861. currsize,
  862. foundsize,
  863. sizeleft,
  864. s : longint;
  865. wasbeforeheapend : boolean;
  866. hp,
  867. pnew,
  868. pcurr : pfreerecord;
  869. begin
  870. { fix needed size }
  871. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  872. { fix p to point to the heaprecord }
  873. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  874. currsize:=pcurr^.size and sizemask;
  875. oldsize:=currsize;
  876. wasbeforeheapend:=(pcurr^.size and beforeheapendmask)<>0;
  877. { is the allocated block still correct? }
  878. if currsize=size then
  879. begin
  880. SysTryResizeMem:=true;
  881. {$ifdef TestFreeLists}
  882. if test_each then
  883. TestFreeLists;
  884. {$endif TestFreeLists}
  885. exit;
  886. end;
  887. { do we need to allocate more memory ? }
  888. if size>currsize then
  889. begin
  890. { the size is bigger than the previous size, we need to allocated more mem.
  891. We first check if the blocks after the current block are free. If not we
  892. simply call getmem/freemem to get the new block }
  893. foundsize:=0;
  894. hp:=pcurr;
  895. repeat
  896. inc(foundsize,hp^.size and sizemask);
  897. { block used or before a heapptr ? }
  898. if (hp^.size and beforeheapendmask)<>0 then
  899. begin
  900. wasbeforeheapend:=true;
  901. break;
  902. end;
  903. { get next block }
  904. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  905. { when we're at heapptr then we can stop }
  906. if (hp=heapptr) then
  907. begin
  908. inc(foundsize,heapend-heapptr);
  909. break;
  910. end;
  911. if (hp^.size and usedmask)<>0 then
  912. break;
  913. until (foundsize>=size);
  914. { found enough free blocks? }
  915. if foundsize>=size then
  916. begin
  917. { we walk the list again and remove all blocks }
  918. foundsize:=pcurr^.size and sizemask;
  919. hp:=pcurr;
  920. repeat
  921. { get next block }
  922. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  923. { when we're at heapptr then we can increase it, if there is enough
  924. room is already checked }
  925. if (hp=heapptr) then
  926. begin
  927. inc(heapptr,size-foundsize);
  928. foundsize:=size;
  929. if (heapend-heapptr)<sizeof(tfreerecord) then
  930. wasbeforeheapend:=true;
  931. break;
  932. end;
  933. s:=hp^.size and sizemask;
  934. inc(foundsize,s);
  935. { remove block from freelist }
  936. s:=s shr blockshr;
  937. if s>maxblock then
  938. s:=0;
  939. if assigned(hp^.next) then
  940. hp^.next^.prev:=hp^.prev;
  941. if assigned(hp^.prev) then
  942. hp^.prev^.next:=hp^.next
  943. else
  944. freelists[s]:=hp^.next;
  945. {$ifdef SYSTEMDEBUG}
  946. dec(freecount[s]);
  947. {$endif SYSTEMDEBUG}
  948. until (foundsize>=size);
  949. if wasbeforeheapend then
  950. pcurr^.size:=foundsize or usedmask or beforeheapendmask
  951. else
  952. pcurr^.size:=foundsize or usedmask;
  953. end
  954. else
  955. begin
  956. { we need to call getmem/move/freemem }
  957. SysTryResizeMem:=false;
  958. {$ifdef TestFreeLists}
  959. if test_each then
  960. TestFreeLists;
  961. {$endif TestFreeLists}
  962. exit;
  963. end;
  964. currsize:=pcurr^.size and sizemask;
  965. end;
  966. { is the size smaller then we can adjust the block to that size and insert
  967. the other part into the freelist }
  968. if size<currsize then
  969. begin
  970. { create the left over freelist block, if at least 16 bytes are free }
  971. sizeleft:=currsize-size;
  972. if sizeleft>sizeof(tfreerecord) then
  973. begin
  974. pnew:=pfreerecord(pointer(pcurr)+size);
  975. pnew^.size:=sizeleft or (pcurr^.size and beforeheapendmask);
  976. { insert the block in the freelist }
  977. pnew^.prev:=nil;
  978. s:=sizeleft shr blockshr;
  979. if s>maxblock then
  980. s:=0;
  981. pnew^.next:=freelists[s];
  982. if assigned(freelists[s]) then
  983. freelists[s]^.prev:=pnew;
  984. freelists[s]:=pnew;
  985. {$ifdef SYSTEMDEBUG}
  986. inc(freecount[s]);
  987. {$endif SYSTEMDEBUG}
  988. { fix the size of the current block and leave }
  989. pcurr^.size:=size or usedmask;
  990. end
  991. else
  992. begin
  993. { fix the size of the current block and leave }
  994. pcurr^.size:=size or usedmask or (pcurr^.size and beforeheapendmask);
  995. end;
  996. end;
  997. dec(internal_memavail,size-oldsize);
  998. SysTryResizeMem:=true;
  999. {$ifdef TestFreeLists}
  1000. if test_each then
  1001. TestFreeLists;
  1002. {$endif TestFreeLists}
  1003. end;
  1004. {*****************************************************************************
  1005. SysResizeMem
  1006. *****************************************************************************}
  1007. function SysReAllocMem(var p:pointer;size : longint):pointer;
  1008. var
  1009. oldsize : longint;
  1010. p2 : pointer;
  1011. begin
  1012. { Free block? }
  1013. if size=0 then
  1014. begin
  1015. if p<>nil then
  1016. begin
  1017. MemoryManager.FreeMem(p);
  1018. p:=nil;
  1019. end;
  1020. end
  1021. else
  1022. { Allocate a new block? }
  1023. if p=nil then
  1024. begin
  1025. p:=MemoryManager.GetMem(size);
  1026. end
  1027. else
  1028. { Resize block }
  1029. if not SysTryResizeMem(p,size) then
  1030. begin
  1031. oldsize:=MemoryManager.MemSize(p);
  1032. p2:=MemoryManager.GetMem(size);
  1033. if p2<>nil then
  1034. Move(p^,p2^,oldsize);
  1035. MemoryManager.FreeMem(p);
  1036. p:=p2;
  1037. end;
  1038. SysReAllocMem:=p;
  1039. end;
  1040. {*****************************************************************************
  1041. Mark/Release
  1042. *****************************************************************************}
  1043. procedure release(var p : pointer);
  1044. begin
  1045. end;
  1046. procedure mark(var p : pointer);
  1047. begin
  1048. end;
  1049. {*****************************************************************************
  1050. Grow Heap
  1051. *****************************************************************************}
  1052. function growheap(size :longint) : integer;
  1053. var
  1054. sizeleft,s1,
  1055. NewPos : longint;
  1056. pcurr : pfreerecord;
  1057. begin
  1058. {$ifdef DUMPGROW}
  1059. writeln('growheap(',size,') allocating ',(size+$ffff) and $ffff0000);
  1060. DumpBlocks;
  1061. {$endif}
  1062. { Allocate by 64K size }
  1063. size:=(size+$ffff) and $ffff0000;
  1064. { first try 256K (default) }
  1065. if size<=GrowHeapSize1 then
  1066. begin
  1067. NewPos:=Sbrk(GrowHeapSize1);
  1068. if NewPos<>-1 then
  1069. size:=GrowHeapSize1;
  1070. end
  1071. else
  1072. { second try 1024K (default) }
  1073. if size<=GrowHeapSize2 then
  1074. begin
  1075. NewPos:=Sbrk(GrowHeapSize2);
  1076. if NewPos<>-1 then
  1077. size:=GrowHeapSize2;
  1078. end
  1079. { else alloate the needed bytes }
  1080. else
  1081. NewPos:=SBrk(size);
  1082. { try again }
  1083. if NewPos=-1 then
  1084. begin
  1085. NewPos:=Sbrk(size);
  1086. if NewPos=-1 then
  1087. begin
  1088. if ReturnNilIfGrowHeapFails then
  1089. GrowHeap:=1
  1090. else
  1091. GrowHeap:=0;
  1092. Exit;
  1093. end;
  1094. end;
  1095. { increase heapend or add to freelist }
  1096. if heapend=pointer(newpos) then
  1097. begin
  1098. heapend:=pointer(newpos+size);
  1099. end
  1100. else
  1101. begin
  1102. { create freelist entry for old heapptr-heapend }
  1103. sizeleft:=heapend-heapptr;
  1104. if sizeleft>=sizeof(tfreerecord) then
  1105. begin
  1106. pcurr:=pfreerecord(heapptr);
  1107. pcurr^.size:=sizeleft or beforeheapendmask;
  1108. { insert the block in the freelist }
  1109. s1:=sizeleft shr blockshr;
  1110. if s1>maxblock then
  1111. s1:=0;
  1112. pcurr^.next:=freelists[s1];
  1113. pcurr^.prev:=nil;
  1114. if assigned(freelists[s1]) then
  1115. freelists[s1]^.prev:=pcurr;
  1116. freelists[s1]:=pcurr;
  1117. {$ifdef SYSTEMDEBUG}
  1118. inc(freecount[s1]);
  1119. {$endif SYSTEMDEBUG}
  1120. end;
  1121. { now set the new heapptr,heapend to the new block }
  1122. heapptr:=pointer(newpos);
  1123. heapend:=pointer(newpos+size);
  1124. end;
  1125. { set the total new heap size }
  1126. inc(internal_memavail,size);
  1127. inc(internal_heapsize,size);
  1128. { try again }
  1129. GrowHeap:=2;
  1130. {$ifdef TestFreeLists}
  1131. TestFreeLists;
  1132. {$endif TestFreeLists}
  1133. end;
  1134. {*****************************************************************************
  1135. InitHeap
  1136. *****************************************************************************}
  1137. { This function will initialize the Heap manager and need to be called from
  1138. the initialization of the system unit }
  1139. procedure InitHeap;
  1140. begin
  1141. FillChar(FreeLists,sizeof(TFreeLists),0);
  1142. {$ifdef SYSTEMDEBUG}
  1143. FillChar(FreeCount,sizeof(TFreeCount),0);
  1144. {$endif SYSTEMDEBUG}
  1145. internal_heapsize:=GetHeapSize;
  1146. internal_memavail:=internal_heapsize;
  1147. HeapOrg:=GetHeapStart;
  1148. HeapPtr:=HeapOrg;
  1149. HeapEnd:=HeapOrg+internal_memavail;
  1150. HeapError:=@GrowHeap;
  1151. {$ifdef MT}
  1152. InitCriticalSection(cs_systemheap);
  1153. {$endif MT}
  1154. end;
  1155. {
  1156. $Log$
  1157. Revision 1.13 2002-04-21 18:56:59 peter
  1158. * fpc_freemem and fpc_getmem compilerproc
  1159. Revision 1.12 2002/02/10 15:33:45 carl
  1160. * fixed some missing IsMultiThreaded variables
  1161. Revision 1.11 2002/01/02 13:43:09 jonas
  1162. * fix for web bug 1727 from Peter (corrected)
  1163. Revision 1.9 2001/12/03 21:39:20 peter
  1164. * freemem(var) -> freemem(value)
  1165. Revision 1.8 2001/10/25 21:22:34 peter
  1166. * moved locking of heap
  1167. Revision 1.7 2001/10/23 21:51:03 peter
  1168. * criticalsection renamed to rtlcriticalsection for kylix compatibility
  1169. Revision 1.6 2001/06/06 17:20:22 jonas
  1170. * fixed wrong typed constant procvars in preparation of my fix which will
  1171. disallow them in FPC mode (plus some other unmerged changes since
  1172. LAST_MERGE)
  1173. Revision 1.5 2001/01/24 21:47:18 florian
  1174. + more MT stuff added
  1175. Revision 1.4 2000/08/08 19:22:46 peter
  1176. * smallatheapptr undef and other cleanup (merged)
  1177. Revision 1.3 2000/07/14 10:33:10 michael
  1178. + Conditionals fixed
  1179. Revision 1.2 2000/07/13 11:33:43 michael
  1180. + removed logs
  1181. }