heap.inc 31 KB

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