heap.inc 30 KB

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