heap.inc 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  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(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. end;
  183. function MaxAvail:Longint;
  184. begin
  185. {$ifdef MT}
  186. if IsMultiThreaded 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 IsMultiThreaded 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 IsMultiThreaded 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 IsMultiThreaded 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 IsMultiThreaded 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 IsMultiThreaded 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 IsMultiThreaded 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 IsMultiThreaded 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 AsmGetMem(size:longint):pointer;compilerproc;[public,alias:'FPC_GETMEM'];
  332. begin
  333. {$ifdef MT}
  334. if IsMultiThreaded then
  335. begin
  336. try
  337. EnterCriticalSection(cs_systemheap);
  338. AsmGetMem:=MemoryManager.GetMem(size);
  339. finally
  340. LeaveCriticalSection(cs_systemheap);
  341. end;
  342. end
  343. else
  344. {$endif MT}
  345. begin
  346. AsmGetMem:=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 AsmFreeMem(p:pointer);compilerproc;[public,alias:'FPC_FREEMEM'];
  358. begin
  359. {$ifdef MT}
  360. if IsMultiThreaded 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. 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. MemoryManager.FreeMem(p);
  1015. end
  1016. else
  1017. { Allocate a new block? }
  1018. if p=nil then
  1019. begin
  1020. p:=MemoryManager.GetMem(size);
  1021. end
  1022. else
  1023. { Resize block }
  1024. if not SysTryResizeMem(p,size) then
  1025. begin
  1026. oldsize:=MemoryManager.MemSize(p);
  1027. p2:=MemoryManager.GetMem(size);
  1028. if p2<>nil then
  1029. Move(p^,p2^,oldsize);
  1030. MemoryManager.FreeMem(p);
  1031. p:=p2;
  1032. end;
  1033. SysReAllocMem:=p;
  1034. end;
  1035. {*****************************************************************************
  1036. Mark/Release
  1037. *****************************************************************************}
  1038. procedure release(var p : pointer);
  1039. begin
  1040. end;
  1041. procedure mark(var p : pointer);
  1042. begin
  1043. end;
  1044. {*****************************************************************************
  1045. Grow Heap
  1046. *****************************************************************************}
  1047. function growheap(size :longint) : integer;
  1048. var
  1049. sizeleft,s1,
  1050. NewPos : longint;
  1051. pcurr : pfreerecord;
  1052. begin
  1053. {$ifdef DUMPGROW}
  1054. writeln('grow ',size);
  1055. DumpBlocks;
  1056. {$endif}
  1057. { Allocate by 64K size }
  1058. size:=(size+$ffff) and $ffff0000;
  1059. { first try 256K (default) }
  1060. if size<=GrowHeapSize1 then
  1061. begin
  1062. NewPos:=Sbrk(GrowHeapSize1);
  1063. if NewPos<>-1 then
  1064. size:=GrowHeapSize1;
  1065. end
  1066. else
  1067. { second try 1024K (default) }
  1068. if size<=GrowHeapSize2 then
  1069. begin
  1070. NewPos:=Sbrk(GrowHeapSize2);
  1071. if NewPos<>-1 then
  1072. size:=GrowHeapSize2;
  1073. end
  1074. { else alloate the needed bytes }
  1075. else
  1076. NewPos:=SBrk(size);
  1077. { try again }
  1078. if NewPos=-1 then
  1079. begin
  1080. NewPos:=Sbrk(size);
  1081. if NewPos=-1 then
  1082. begin
  1083. if ReturnNilIfGrowHeapFails then
  1084. GrowHeap:=1
  1085. else
  1086. GrowHeap:=0;
  1087. Exit;
  1088. end;
  1089. end;
  1090. { increase heapend or add to freelist }
  1091. if heapend=pointer(newpos) then
  1092. begin
  1093. heapend:=pointer(newpos+size);
  1094. end
  1095. else
  1096. begin
  1097. { create freelist entry for old heapptr-heapend }
  1098. sizeleft:=heapend-heapptr;
  1099. if sizeleft>=sizeof(tfreerecord) then
  1100. begin
  1101. pcurr:=pfreerecord(heapptr);
  1102. pcurr^.size:=sizeleft or beforeheapendmask;
  1103. { insert the block in the freelist }
  1104. s1:=sizeleft shr blockshr;
  1105. if s1>maxblock then
  1106. s1:=0;
  1107. pcurr^.next:=freelists[s1];
  1108. pcurr^.prev:=nil;
  1109. if assigned(freelists[s1]) then
  1110. freelists[s1]^.prev:=pcurr;
  1111. freelists[s1]:=pcurr;
  1112. {$ifdef SYSTEMDEBUG}
  1113. inc(freecount[s1]);
  1114. {$endif SYSTEMDEBUG}
  1115. end;
  1116. { now set the new heapptr,heapend to the new block }
  1117. heapptr:=pointer(newpos);
  1118. heapend:=pointer(newpos+size);
  1119. end;
  1120. { set the total new heap size }
  1121. inc(internal_memavail,size);
  1122. inc(internal_heapsize,size);
  1123. { try again }
  1124. GrowHeap:=2;
  1125. {$ifdef TestFreeLists}
  1126. TestFreeLists;
  1127. {$endif TestFreeLists}
  1128. end;
  1129. {*****************************************************************************
  1130. InitHeap
  1131. *****************************************************************************}
  1132. { This function will initialize the Heap manager and need to be called from
  1133. the initialization of the system unit }
  1134. procedure InitHeap;
  1135. begin
  1136. FillChar(FreeLists,sizeof(TFreeLists),0);
  1137. {$ifdef SYSTEMDEBUG}
  1138. FillChar(FreeCount,sizeof(TFreeCount),0);
  1139. {$endif SYSTEMDEBUG}
  1140. internal_heapsize:=GetHeapSize;
  1141. internal_memavail:=internal_heapsize;
  1142. HeapOrg:=GetHeapStart;
  1143. HeapPtr:=HeapOrg;
  1144. HeapEnd:=HeapOrg+internal_memavail;
  1145. HeapError:=@GrowHeap;
  1146. {$ifdef MT}
  1147. InitCriticalSection(cs_systemheap);
  1148. {$endif MT}
  1149. end;
  1150. {
  1151. $Log$
  1152. Revision 1.9 2001-12-03 21:39:20 peter
  1153. * freemem(var) -> freemem(value)
  1154. Revision 1.8 2001/10/25 21:22:34 peter
  1155. * moved locking of heap
  1156. Revision 1.7 2001/10/23 21:51:03 peter
  1157. * criticalsection renamed to rtlcriticalsection for kylix compatibility
  1158. Revision 1.6 2001/06/06 17:20:22 jonas
  1159. * fixed wrong typed constant procvars in preparation of my fix which will
  1160. disallow them in FPC mode (plus some other unmerged changes since
  1161. LAST_MERGE)
  1162. Revision 1.5 2001/01/24 21:47:18 florian
  1163. + more MT stuff added
  1164. Revision 1.4 2000/08/08 19:22:46 peter
  1165. * smallatheapptr undef and other cleanup (merged)
  1166. Revision 1.3 2000/07/14 10:33:10 michael
  1167. + Conditionals fixed
  1168. Revision 1.2 2000/07/13 11:33:43 michael
  1169. + removed logs
  1170. }