heap.inc 35 KB

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