heap.inc 28 KB

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