heap.inc 32 KB

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