heap.inc 36 KB

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