heap.inc 33 KB

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