heap.inc 36 KB

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