heap.inc 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993-98 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. Supported conditionnals:
  14. ------------------------
  15. TEMPHEAP to allow to split the heap in two parts for easier release
  16. started for the compiler
  17. CHECKHEAP if you want to test the heap integrity
  18. }
  19. { Memory manager }
  20. const
  21. MemoryManager: TMemoryManager = (
  22. GetMem: SysGetMem;
  23. FreeMem: SysFreeMem
  24. );
  25. { Default Heap }
  26. const
  27. max_size = 256;
  28. maxblock = max_size div 8;
  29. type
  30. ppointer = ^pointer;
  31. pfreerecord = ^tfreerecord;
  32. tfreerecord = record
  33. next : pfreerecord;
  34. size : longint;
  35. end;
  36. tblocks = array[1..maxblock] of pointer;
  37. pblocks = ^tblocks;
  38. tnblocks = array[1..maxblock] of longint;
  39. pnblocks = ^tnblocks;
  40. var
  41. internal_memavail : longint;
  42. internal_heapsize : longint;
  43. baseblocks : tblocks;
  44. basenblocks : tnblocks;
  45. const
  46. blocks : pblocks = @baseblocks;
  47. nblocks : pnblocks = @basenblocks;
  48. { Check Heap }
  49. {$IfDef CHECKHEAP}
  50. { 4 levels of tracing }
  51. const
  52. tracesize = 4;
  53. freerecord_list_length : longint = 0;
  54. type
  55. pheap_mem_info = ^heap_mem_info;
  56. heap_mem_info = record
  57. next,
  58. previous : pheap_mem_info;
  59. size : longint;
  60. sig : longint; {dummy number for test }
  61. calls : array [1..tracesize] of longint;
  62. end;
  63. { size 8*4 = 32 }
  64. const
  65. { help variables for debugging with GDB }
  66. check : boolean = false;
  67. growheapstop : boolean = false;
  68. free_nothing : boolean = false;
  69. trace : boolean = true;
  70. var
  71. last_assigned : pheap_mem_info;
  72. getmem_nb : longint;
  73. freemem_nb : longint;
  74. {$EndIf CHECKHEAP}
  75. { Temp Heap }
  76. {$ifdef TEMPHEAP}
  77. const
  78. heap_split : boolean = false;
  79. type
  80. pheapinfo = ^theapinfo;
  81. theapinfo = record
  82. heaporg,heapptr,
  83. heapend,freelist : pointer;
  84. memavail,heapsize : longint;
  85. block : pblocks;
  86. nblock : pnblocks;
  87. {$IfDef CHECKHEAP}
  88. last_mem : pheap_mem_info;
  89. nb_get,
  90. nb_free : longint;
  91. {$EndIf CHECKHEAP}
  92. end;
  93. var
  94. baseheap : theapinfo;
  95. curheap : pheapinfo;
  96. tempheap : theapinfo;
  97. otherheap : pheapinfo;
  98. {$endif TEMPHEAP}
  99. {*****************************************************************************
  100. Memory Manager
  101. *****************************************************************************}
  102. procedure GetMemoryManager(var MemMgr:TMemoryManager);
  103. begin
  104. MemMgr:=MemoryManager;
  105. end;
  106. procedure SetMemoryManager(const MemMgr:TMemoryManager);
  107. begin
  108. MemoryManager:=MemMgr;
  109. end;
  110. function IsMemoryManagerSet:Boolean;
  111. begin
  112. IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
  113. (MemoryManager.FreeMem<>@SysFreeMem);
  114. end;
  115. procedure GetMem(Var p:pointer;Size:Longint);[public,alias:{$ifdef FPCNAMES}'FPC_'+{$endif}'GETMEM'];
  116. begin
  117. MemoryManager.GetMem(p,Size);
  118. end;
  119. procedure FreeMem(Var p:pointer;Size:Longint);[public,alias:{$ifdef FPCNAMES}'FPC_'+{$endif}'FREEMEM'];
  120. begin
  121. MemoryManager.FreeMem(p,Size);
  122. end;
  123. {*****************************************************************************
  124. Heapsize,Memavail,MaxAvail
  125. *****************************************************************************}
  126. function heapsize : longint;
  127. begin
  128. heapsize:=internal_heapsize;
  129. end;
  130. function memavail : longint;
  131. begin
  132. memavail:=internal_memavail;
  133. end;
  134. function maxavail : longint;
  135. var
  136. hp : pfreerecord;
  137. begin
  138. maxavail:=heapend-heapptr;
  139. hp:=freelist;
  140. while assigned(hp) do
  141. begin
  142. if hp^.size>maxavail then
  143. maxavail:=hp^.size;
  144. hp:=hp^.next;
  145. end;
  146. end;
  147. function calc_memavail : longint;
  148. var
  149. hp : pfreerecord;
  150. ma : longint;
  151. i : longint;
  152. begin
  153. ma:=heapend-heapptr;
  154. { count blocks }
  155. if heapblocks then
  156. for i:=1 to maxblock do
  157. inc(ma,i*8*nblocks^[i]);
  158. { walk freelist }
  159. hp:=freelist;
  160. while assigned(hp) do
  161. begin
  162. inc(ma,hp^.size);
  163. {$IfDef CHECKHEAP}
  164. if (longint(hp^.next)=0) then
  165. begin
  166. if ((longint(hp)+hp^.size)>longint(heapptr)) then
  167. writeln('freerecordlist bad at end ')
  168. end
  169. else
  170. if ((longint(hp^.next)<=(longint(hp)+hp^.size)) or
  171. ((hp^.size and 7) <> 0)) then
  172. writeln('error in freerecord list ');
  173. {$EndIf CHECKHEAP}
  174. hp:=hp^.next;
  175. end;
  176. calc_memavail:=ma;
  177. end;
  178. {*****************************************************************************
  179. Check Heap helpers
  180. *****************************************************************************}
  181. {$IfDef CHECKHEAP}
  182. procedure call_stack(p : pointer);
  183. var
  184. i : longint;
  185. pp : pheap_mem_info;
  186. begin
  187. if trace then
  188. begin
  189. pp:=pheap_mem_info(p-sizeof(heap_mem_info));
  190. writeln('Call trace of 0x',hexstr(longint(p),8));
  191. writeln('of size ',pp^.size);
  192. for i:=1 to tracesize do
  193. writeln(i,' 0x',hexstr(pp^.calls[i],8));
  194. end
  195. else
  196. writeln('tracing not enabled, sorry !!');
  197. end;
  198. procedure dump_heap(mark : boolean);
  199. var
  200. pp : pheap_mem_info;
  201. begin
  202. pp:=last_assigned;
  203. while pp<>nil do
  204. begin
  205. call_stack(pp+sizeof(heap_mem_info));
  206. if mark then
  207. pp^.sig:=$AAAAAAAA;
  208. pp:=pp^.previous;
  209. end;
  210. end;
  211. procedure dump_free(p : pheap_mem_info);
  212. var
  213. ebp : longint;
  214. begin
  215. Writeln('Marked memory at ',HexStr(longint(p),8),' released');
  216. call_stack(p+sizeof(heap_mem_info));
  217. dump_stack(get_caller_frame(get_frame));
  218. end;
  219. function is_in_getmem_list (p : pointer) : boolean;
  220. var
  221. i : longint;
  222. pp : pheap_mem_info;
  223. begin
  224. is_in_getmem_list:=false;
  225. pp:=last_assigned;
  226. i:=0;
  227. while pp<>nil do
  228. begin
  229. if (pp^.sig<>$DEADBEEF) and (pp^.sig <> $AAAAAAAA) then
  230. begin
  231. writeln('error in linked list of heap_mem_info');
  232. HandleError(204);
  233. end
  234. if pp=p then
  235. is_in_getmem_list:=true;
  236. pp:=pp^.previous;
  237. inc(i);
  238. if i > getmem_nb - freemem_nb then
  239. writeln('error in linked list of heap_mem_info');
  240. end;
  241. end;
  242. function is_in_free(p : pointer) : boolean;
  243. var
  244. hp : pfreerecord;
  245. begin
  246. if p>heapptr then
  247. begin
  248. is_in_free:=true;
  249. exit;
  250. end
  251. else
  252. begin
  253. hp:=freelist;
  254. while assigned(hp) do
  255. begin
  256. if (p>=hp) and (p<hp+hp^.size) then
  257. begin
  258. is_in_free:=true;
  259. exit;
  260. end;
  261. hp:=hp^.next;
  262. end;
  263. is_in_free:=false;
  264. end;
  265. end;
  266. procedure test_memavail;
  267. begin
  268. if check and (internal_memavail<>calc_memavail) then
  269. writeln('Memavail error in getmem/freemem');
  270. end;
  271. {$EndIf CHECKHEAP}
  272. {*****************************************************************************
  273. Temp Heap support
  274. *****************************************************************************}
  275. {$ifdef TEMPHEAP}
  276. procedure split_heap;
  277. begin
  278. if not heap_split then
  279. begin
  280. baseheap.heaporg:=heaporg;
  281. baseheap.heapptr:=heapptr;
  282. baseheap.freelist:=freelist;
  283. baseheap.block:=blocks;
  284. baseheap.nblock:=nblocks;
  285. longint(baseheap.heapend):=((longint(heapend)+longint(heapptr)) div 16)*8;
  286. tempheap.heaporg:=baseheap.heapend;
  287. tempheap.freelist:=nil;
  288. tempheap.heapptr:=tempheap.heaporg;
  289. {$IfDef CHECKHEAP}
  290. tempheap.last_mem:=nil;
  291. tempheap.nb_get:=0;
  292. tempheap.nb_free:=0;
  293. {$EndIf CHECKHEAP}
  294. tempheap.heapend:=heapend;
  295. tempheap.memavail:=longint(tempheap.heapend) - longint(tempheap.heaporg);
  296. tempheap.heapsize:=tempheap.memavail;
  297. getmem(tempheap.block,sizeof(tblocks));
  298. getmem(tempheap.nblock,sizeof(tnblocks));
  299. fillchar(tempheap.block^,sizeof(tblocks),0);
  300. fillchar(tempheap.nblock^,sizeof(tnblocks),0);
  301. heapend:=baseheap.heapend;
  302. internal_memavail:=calc_memavail;
  303. baseheap.memavail:=internal_memavail;
  304. baseheap.heapsize:=longint(baseheap.heapend)-longint(baseheap.heaporg);
  305. curheap:=@baseheap;
  306. otherheap:=@tempheap;
  307. heap_split:=true;
  308. end;
  309. end;
  310. procedure switch_to_temp_heap;
  311. begin
  312. if curheap = @baseheap then
  313. begin
  314. baseheap.heaporg:=heaporg;
  315. baseheap.heapend:=heapend;
  316. baseheap.heapptr:=heapptr;
  317. baseheap.freelist:=freelist;
  318. baseheap.memavail:=internal_memavail;
  319. baseheap.block:=blocks;
  320. baseheap.nblock:=nblocks;
  321. {$IfDef CHECKHEAP}
  322. baseheap.last_mem:=last_assigned;
  323. last_assigned:=tempheap.last_mem;
  324. baseheap.nb_get:=getmem_nb;
  325. baseheap.nb_free:=freemem_nb;
  326. getmem_nb:=tempheap.nb_get;
  327. freemem_nb:=tempheap.nb_free;
  328. {$EndIf CHECKHEAP}
  329. heaporg:=tempheap.heaporg;
  330. heapptr:=tempheap.heapptr;
  331. freelist:=tempheap.freelist;
  332. heapend:=tempheap.heapend;
  333. blocks:=tempheap.block;
  334. nblocks:=tempheap.nblock;
  335. internal_memavail:=calc_memavail;
  336. curheap:=@tempheap;
  337. otherheap:=@baseheap;
  338. end;
  339. end;
  340. procedure switch_to_base_heap;
  341. begin
  342. if curheap = @tempheap then
  343. begin
  344. tempheap.heaporg:=heaporg;
  345. tempheap.heapend:=heapend;
  346. tempheap.heapptr:=heapptr;
  347. tempheap.freelist:=freelist;
  348. tempheap.memavail:=internal_memavail;
  349. {$IfDef CHECKHEAP}
  350. tempheap.last_mem:=last_assigned;
  351. last_assigned:=baseheap.last_mem;
  352. tempheap.nb_get:=getmem_nb;
  353. tempheap.nb_free:=freemem_nb;
  354. getmem_nb:=baseheap.nb_get;
  355. freemem_nb:=baseheap.nb_free;
  356. {$EndIf CHECKHEAP}
  357. heaporg:=baseheap.heaporg;
  358. heapptr:=baseheap.heapptr;
  359. freelist:=baseheap.freelist;
  360. heapend:=baseheap.heapend;
  361. blocks:=baseheap.block;
  362. nblocks:=baseheap.nblock;
  363. internal_memavail:=calc_memavail;
  364. curheap:=@baseheap;
  365. otherheap:=@tempheap;
  366. end;
  367. end;
  368. procedure switch_heap;
  369. begin
  370. if not heap_split then
  371. split_heap;
  372. if curheap = @tempheap then
  373. switch_to_base_heap
  374. else
  375. switch_to_temp_heap;
  376. end;
  377. procedure gettempmem(var p : pointer;size : longint);
  378. begin
  379. split_heap;
  380. switch_to_temp_heap;
  381. allow_special:=true;
  382. getmem(p,size);
  383. allow_special:=false;
  384. end;
  385. procedure unsplit_heap;
  386. var
  387. hp,hp2,thp : pfreerecord;
  388. begin
  389. {heapend can be modified by HeapError }
  390. if not heap_split then
  391. exit;
  392. if baseheap.heapend = tempheap.heaporg then
  393. begin
  394. switch_to_base_heap;
  395. hp:=pfreerecord(freelist);
  396. if assigned(hp) then
  397. begin
  398. while assigned(hp^.next) do
  399. hp:=hp^.next;
  400. end;
  401. if tempheap.heapptr<>tempheap.heaporg then
  402. begin
  403. if hp<>nil then
  404. hp^.next:=heapptr;
  405. hp:=pfreerecord(heapptr);
  406. hp^.size:=heapend-heapptr;
  407. hp^.next:=tempheap.freelist;
  408. heapptr:=tempheap.heapptr;
  409. end;
  410. heapend:=tempheap.heapend;
  411. internal_memavail:=calc_memavail;
  412. heap_split:=false;
  413. end
  414. else
  415. begin
  416. hp:=pfreerecord(baseheap.freelist);
  417. hp2:=pfreerecord(tempheap.freelist);
  418. while assigned(hp) and assigned(hp2) do
  419. begin
  420. if hp=hp2 then
  421. break;
  422. if hp>hp2 then
  423. begin
  424. thp:=hp2;
  425. hp2:=hp;
  426. hp:=thp;
  427. end;
  428. while assigned(hp^.next) and (hp^.next<hp2) do
  429. hp:=hp^.next;
  430. if assigned(hp^.next) then
  431. begin
  432. thp:=hp^.next;
  433. hp^.next:=hp2;
  434. hp:=thp;
  435. end
  436. else
  437. begin
  438. hp^.next:=hp2;
  439. hp:=nil;
  440. end;
  441. end;
  442. if heapend < tempheap.heapend then
  443. heapend:=tempheap.heapend;
  444. if heapptr < tempheap.heapptr then
  445. heapptr:=tempheap.heapptr;
  446. freemem(tempheap.block,sizeof(tblocks));
  447. freemem(tempheap.nblock,sizeof(tnblocks));
  448. internal_memavail:=calc_memavail;
  449. heap_split:=false;
  450. end;
  451. end;
  452. procedure releasetempheap;
  453. begin
  454. switch_to_temp_heap;
  455. {$ifdef CHECKHEAP}
  456. if heapptr<>heaporg then
  457. writeln('Warning in releasetempheap : ',longint(tempheap.heapsize)-longint(tempheap.memavail),' bytes used !');
  458. dump_heap(true);
  459. { release(heaporg);
  460. fillchar(heaporg^,longint(heapend)-longint(heaporg),#0); }
  461. {$endif CHECKHEAP }
  462. unsplit_heap;
  463. split_heap;
  464. end;
  465. {$endif TEMPHEAP}
  466. {*****************************************************************************
  467. SysGetMem
  468. *****************************************************************************}
  469. procedure SysGetMem(var p : pointer;size : longint);
  470. type
  471. heaperrorproc=function(size:longint):integer;
  472. var
  473. proc : heaperrorproc;
  474. last,hp : pfreerecord;
  475. again : boolean;
  476. s,hpsize : longint;
  477. {$IfDef CHECKHEAP}
  478. i,bp,orsize : longint;
  479. label
  480. check_new;
  481. {$endif CHECKHEAP}
  482. begin
  483. {$ifdef CHECKHEAP}
  484. if trace then
  485. begin
  486. orsize:=size;
  487. inc(size,sizeof(heap_mem_info));
  488. end;
  489. {$endif CHECKHEAP}
  490. { Something to allocate ? }
  491. if size<=0 then
  492. begin
  493. { give an error for < 0 }
  494. if size<0 then
  495. HandleError(204);
  496. p:=heapend;
  497. {$ifdef CHECKHEAP}
  498. goto check_new;
  499. {$else CHECKHEAP}
  500. exit;
  501. {$endif CHECKHEAP}
  502. end;
  503. { temp heap checking }
  504. {$ifdef TEMPHEAP}
  505. if heap_split and not allow_special then
  506. begin
  507. if (@p < otherheap^.heapend) and (@p > otherheap^.heaporg) then
  508. { useful line for the debugger }
  509. writeln('warning : p and @p are in different heaps !');
  510. end;
  511. {$endif TEMPHEAP}
  512. { calc to multiply of 8 }
  513. size:=(size+7) and (not 7);
  514. dec(internal_memavail,size);
  515. { first try heap blocks }
  516. if heapblocks then
  517. begin
  518. { search cache }
  519. if size<=max_size then
  520. begin
  521. s:=size shr 3;
  522. p:=blocks^[s];
  523. if assigned(p) then
  524. begin
  525. blocks^[s]:=pointer(p^);
  526. dec(nblocks^[s]);
  527. {$ifdef CHECKHEAP}
  528. goto check_new;
  529. {$else CHECKHEAP}
  530. exit;
  531. {$endif CHECKHEAP}
  532. end;
  533. end;
  534. end;
  535. { walk free list }
  536. repeat
  537. again:=false;
  538. { search the freelist }
  539. if assigned(freelist) then
  540. begin
  541. last:=nil;
  542. hp:=freelist;
  543. while assigned(hp) do
  544. begin
  545. hpsize:=hp^.size;
  546. { take the first fitting block }
  547. if hpsize>=size then
  548. begin
  549. p:=hp;
  550. { need we the whole block ? }
  551. if (hpsize>size) and heapblocks then
  552. begin
  553. { we must check if we are still below the limit !! }
  554. if hpsize-size<=max_size then
  555. begin
  556. { adjust the list }
  557. if assigned(last) then
  558. last^.next:=hp^.next
  559. else
  560. freelist:=hp^.next;
  561. { insert in chain }
  562. s:=(hpsize-size) div 8;
  563. ppointer(hp+size)^:=blocks^[s];
  564. blocks^[s]:=hp+size;
  565. inc(nblocks^[s]);
  566. end
  567. else
  568. begin
  569. (hp+size)^.size:=hpsize-size;
  570. (hp+size)^.next:=hp^.next;
  571. if assigned(last) then
  572. last^.next:=hp+size
  573. else
  574. freelist:=hp+size;
  575. end;
  576. end
  577. else
  578. begin
  579. {$IfDef CHECKHEAP}
  580. dec(freerecord_list_length);
  581. {$endif CHECKHEAP}
  582. if assigned(last) then
  583. last^.next:=hp^.next
  584. else
  585. freelist:=hp^.next;
  586. end;
  587. {$ifdef CHECKHEAP}
  588. goto check_new;
  589. {$else CHECKHEAP}
  590. exit;
  591. {$endif CHECKHEAP}
  592. end;
  593. last:=hp;
  594. hp:=hp^.next;
  595. end;
  596. end;
  597. { Latly, the top of the heap is checked, to see if there is }
  598. { still memory available. }
  599. if heapend-heapptr<size then
  600. begin
  601. if assigned(heaperror) then
  602. begin
  603. proc:=heaperrorproc(heaperror);
  604. case proc(size) of
  605. 0 : HandleError(203);
  606. 1 : p:=nil;
  607. 2 : again:=true;
  608. end;
  609. end
  610. else
  611. HandleError(203);
  612. end
  613. else
  614. begin
  615. p:=heapptr;
  616. inc(heapptr,size);
  617. end;
  618. until not again;
  619. {$ifdef CHECKHEAP}
  620. check_new:
  621. inc(getmem_nb);
  622. test_memavail;
  623. if trace then
  624. begin
  625. pheap_mem_info(p)^.sig:=$DEADBEEF;
  626. pheap_mem_info(p)^.previous:=last_assigned;
  627. if last_assigned<>nil then
  628. last_assigned^.next:=pheap_mem_info(p);
  629. last_assigned:=p;
  630. pheap_mem_info(p)^.next:=nil;
  631. pheap_mem_info(p)^.size:=orsize;
  632. bp:=get_caller_frame(get_frame);
  633. for i:=1 to tracesize do
  634. begin
  635. pheap_mem_info(p)^.calls[i]:=get_caller_addr(bp);
  636. bp:=get_caller_frame(bp);
  637. end;
  638. inc(p,sizeof(heap_mem_info));
  639. end;
  640. {$endif CHECKHEAP}
  641. end;
  642. {*****************************************************************************
  643. SysFreeMem
  644. *****************************************************************************}
  645. procedure SysFreeMem(var p : pointer;size : longint);
  646. var
  647. hp : pfreerecord;
  648. {$ifdef TEMPHEAP}
  649. heap_switched : boolean;
  650. {$endif TEMPHEAP}
  651. s : longint;
  652. label
  653. freemem_exit;
  654. begin
  655. if size<=0 then
  656. begin
  657. if size<0 then
  658. HandleError(204);
  659. p:=nil;
  660. exit;
  661. end;
  662. if p=nil then
  663. HandleError(204);
  664. {$ifdef CHECKHEAP}
  665. if free_nothing then
  666. begin
  667. p:=nil;
  668. exit;
  669. end;
  670. if trace then
  671. begin
  672. inc(size,sizeof(heap_mem_info));
  673. dec(p,sizeof(heap_mem_info));
  674. end;
  675. {$endif CHECKHEAP}
  676. {$ifdef TEMPHEAP}
  677. heap_switched:=false;
  678. if heap_split and not allow_special then
  679. begin
  680. if (p<=heapptr) and (p>=heaporg) and
  681. (@p<=otherheap^.heapend) and (@p>=otherheap^.heaporg) then
  682. writeln('warning : p and @p are in different heaps !');
  683. end;
  684. if (p<heaporg) or (p>heapptr) then
  685. begin
  686. if heap_split and (p<otherheap^.heapend) and (p>otherheap^.heaporg) then
  687. begin
  688. if (@p>=heaporg) and (@p<=heapptr) and not allow_special then
  689. writeln('warning : p and @p are in different heaps !');
  690. switch_heap;
  691. heap_switched:=true;
  692. end
  693. else
  694. begin
  695. writeln('pointer ',hexstr(longint(@p),8),' at ',hexstr(longint(p),8),' doesn''t points to the heap');
  696. HandleError(204);
  697. end;
  698. end;
  699. {$endif TEMPHEAP}
  700. {$ifdef CHECKHEAP}
  701. if trace then
  702. begin
  703. if not (is_in_getmem_list(p)) then
  704. HandleError(204);
  705. if pheap_mem_info(p)^.sig=$AAAAAAAA then
  706. dump_free(p);
  707. if pheap_mem_info(p)^.next<>nil then
  708. pheap_mem_info(p)^.next^.previous:=pheap_mem_info(p)^.previous;
  709. if pheap_mem_info(p)^.previous<>nil then
  710. pheap_mem_info(p)^.previous^.next:=pheap_mem_info(p)^.next;
  711. if pheap_mem_info(p)=last_assigned then
  712. last_assigned:=last_assigned^.previous;
  713. end;
  714. {$endif CHECKHEAP}
  715. { calc to multiple of 8 }
  716. size:=(size+7) and (not 7);
  717. inc(internal_memavail,size);
  718. { end of the heap ? }
  719. if p+size>=heapptr then
  720. begin
  721. heapptr:=p;
  722. goto freemem_exit;
  723. end;
  724. { heap block? }
  725. if heapblocks and (size<=max_size) then
  726. begin
  727. s:=size shr 3;
  728. ppointer(p)^:=blocks^[s];
  729. blocks^[s]:=p;
  730. inc(nblocks^[s]);
  731. end
  732. else
  733. begin
  734. { size can be allways set }
  735. pfreerecord(p)^.size:=size;
  736. { if there is no free list }
  737. if not assigned(freelist) then
  738. begin
  739. { then generate one }
  740. freelist:=p;
  741. pfreerecord(p)^.next:=nil;
  742. {$ifdef CHECKHEAP}
  743. inc(freerecord_list_length);
  744. {$endif CHECKHEAP}
  745. goto freemem_exit;
  746. end;
  747. if p+size<freelist then
  748. begin
  749. pfreerecord(p)^.next:=freelist;
  750. freelist:=p;
  751. {$ifdef CHECKHEAP}
  752. inc(freerecord_list_length);
  753. {$endif CHECKHEAP}
  754. goto freemem_exit;
  755. end
  756. else
  757. if p+size=freelist then
  758. begin
  759. pfreerecord(p)^.size:=Pfreerecord(p)^.size+pfreerecord(freelist)^.size;
  760. pfreerecord(p)^.next:=pfreerecord(freelist)^.next;
  761. freelist:=p;
  762. { but now it can also connect the next block !!}
  763. if p+pfreerecord(p)^.size=pfreerecord(p)^.next then
  764. begin
  765. pfreerecord(p)^.size:=pfreerecord(p)^.size+pfreerecord(p)^.next^.size;
  766. {$ifdef CHECKHEAP}
  767. dec(freerecord_list_length);
  768. {$endif CHECKHEAP}
  769. pfreerecord(p)^.next:=pfreerecord(freelist)^.next^.next;
  770. end;
  771. goto freemem_exit;
  772. end;
  773. { insert block in freelist }
  774. hp:=freelist;
  775. while assigned(hp) do
  776. begin
  777. if p<hp+hp^.size then
  778. begin
  779. {$ifdef CHECKHEAP}
  780. writeln('pointer to dispose at ',hexstr(longint(p),8),' has already been disposed');
  781. {$endif CHECKHEAP}
  782. HandleError(204);
  783. end;
  784. { connecting two blocks ? }
  785. if hp+hp^.size=p then
  786. begin
  787. inc(hp^.size,size);
  788. { connecting also to next block ? }
  789. if hp+hp^.size=hp^.next then
  790. begin
  791. inc(hp^.size,hp^.next^.size);
  792. {$ifdef CHECKHEAP}
  793. dec(freerecord_list_length);
  794. {$endif CHECKHEAP}
  795. hp^.next:=hp^.next^.next;
  796. end
  797. else
  798. if (hp^.next<>nil) and (hp+hp^.size>hp^.next) then
  799. begin
  800. {$ifdef CHECKHEAP}
  801. writeln('pointer to dispose at ',hexstr(longint(p),8),' is too big !!');
  802. {$endif CHECKHEAP}
  803. HandleError(204);
  804. end;
  805. break;
  806. end
  807. { if the end is reached, then concat }
  808. else
  809. if hp^.next=nil then
  810. begin
  811. hp^.next:=p;
  812. {$ifdef CHECKHEAP}
  813. inc(freerecord_list_length);
  814. {$endif CHECKHEAP}
  815. pfreerecord(p)^.next:=nil;
  816. break;
  817. end
  818. { if next pointer is greater, then insert }
  819. else
  820. if hp^.next>p then
  821. begin
  822. { connect to blocks }
  823. if p+size=hp^.next then
  824. begin
  825. pfreerecord(p)^.next:=hp^.next^.next;
  826. pfreerecord(p)^.size:=pfreerecord(p)^.size+hp^.next^.size;
  827. { we have to reset the right position }
  828. hp^.next:=pfreerecord(p);
  829. end
  830. else
  831. begin
  832. pfreerecord(p)^.next:=hp^.next;
  833. hp^.next:=p;
  834. {$ifdef CHECKHEAP}
  835. inc(freerecord_list_length);
  836. {$endif CHECKHEAP}
  837. end;
  838. break;
  839. end;
  840. hp:=hp^.next;
  841. end;
  842. end;
  843. freemem_exit:
  844. {$ifdef CHECKHEAP}
  845. inc(freemem_nb);
  846. test_memavail;
  847. {$endif CHECKHEAP}
  848. {$ifdef TEMPHEAP}
  849. if heap_switched then
  850. switch_heap;
  851. {$endif TEMPHEAP}
  852. p:=nil;
  853. end;
  854. {*****************************************************************************
  855. Mark/Release
  856. *****************************************************************************}
  857. procedure release(var p : pointer);
  858. begin
  859. heapptr:=p;
  860. freelist:=nil;
  861. internal_memavail:=calc_memavail;
  862. end;
  863. procedure mark(var p : pointer);
  864. begin
  865. p:=heapptr;
  866. end;
  867. procedure markheap(var oldfreelist,oldheapptr : pointer);
  868. begin
  869. oldheapptr:=heapptr;
  870. oldfreelist:=freelist;
  871. freelist:=nil;
  872. internal_memavail:=calc_memavail;
  873. end;
  874. procedure releaseheap(oldfreelist,oldheapptr : pointer);
  875. begin
  876. heapptr:=oldheapptr;
  877. if longint(freelist) < longint(heapptr) then
  878. begin
  879. { here we should reget the freed blocks }
  880. end;
  881. freelist:=oldfreelist;
  882. internal_memavail:=calc_memavail;
  883. end;
  884. {*****************************************************************************
  885. Grow Heap
  886. *****************************************************************************}
  887. function growheap(size :longint) : integer;
  888. var
  889. {$ifdef CHECKHEAP}
  890. NewLimit,
  891. {$endif CHECKHEAP}
  892. NewPos,
  893. wantedsize : longint;
  894. hp : pfreerecord;
  895. begin
  896. wantedsize:=size;
  897. { Allocate by 64K size }
  898. size:=(size+$fffff) and $ffff0000;
  899. { first try 1Meg }
  900. if size<GrowHeapSize then
  901. begin
  902. NewPos:=Sbrk(GrowHeapSize);
  903. if NewPos>0 then
  904. size:=GrowHeapSize;
  905. end
  906. else
  907. NewPos:=SBrk(size);
  908. { try again }
  909. if NewPos=-1 then
  910. begin
  911. NewPos:=Sbrk(size);
  912. if NewPos=-1 then
  913. begin
  914. GrowHeap:=0;
  915. {$IfDef CHECKHEAP}
  916. writeln('Call to GrowHeap failed');
  917. readln;
  918. {$EndIf CHECKHEAP}
  919. Exit;
  920. end;
  921. end;
  922. { make the room clean }
  923. {$ifdef CHECKHEAP}
  924. Fillword(pointer(NewPos)^,size div 2,$ABCD);
  925. Newlimit:=(newpos+size) or $3fff;
  926. {$endif CHECKHEAP}
  927. hp:=pfreerecord(freelist);
  928. if not assigned(hp) then
  929. begin
  930. if pointer(newpos) = heapend then
  931. heapend:=pointer(newpos+size)
  932. else
  933. begin
  934. if heapend - heapptr > 0 then
  935. begin
  936. freelist:=heapptr;
  937. hp:=pfreerecord(freelist);
  938. hp^.size:=heapend-heapptr;
  939. hp^.next:=nil;
  940. end;
  941. heapptr:=pointer(newpos);
  942. heapend:=pointer(newpos+size);
  943. end;
  944. end
  945. else
  946. begin
  947. if pointer(newpos) = heapend then
  948. heapend:=pointer(newpos+size)
  949. else
  950. begin
  951. while assigned(hp^.next) and (longint(hp^.next) < longint(NewPos)) do
  952. hp:=hp^.next;
  953. if hp^.next = nil then
  954. begin
  955. hp^.next:=pfreerecord(heapptr);
  956. hp:=pfreerecord(heapptr);
  957. hp^.size:=heapend-heapptr;
  958. hp^.next:=nil;
  959. heapptr:=pointer(NewPos);
  960. heapend:=pointer(NewPos+Size);
  961. end
  962. else
  963. begin
  964. pfreerecord(NewPos)^.Size:=Size;
  965. pfreerecord(NewPos)^.Next:=hp^.next;
  966. hp^.next:=pfreerecord(NewPos);
  967. end;
  968. end;
  969. end;
  970. { the wanted size has to be substracted
  971. why it will be substracted in the second try
  972. to get the memory PM }
  973. internal_memavail:=calc_memavail;
  974. { set the total new heap size }
  975. inc(internal_heapsize,size);
  976. { try again }
  977. GrowHeap:=2;
  978. {$IfDef CHECKHEAP}
  979. writeln('Call to GrowHeap succedeed : HeapSize = ',internal_heapsize,' MemAvail = ',memavail);
  980. writeln('New heap part begins at ',Newpos,' with size ',size);
  981. if growheapstop then
  982. readln;
  983. {$EndIf CHECKHEAP}
  984. end;
  985. {*****************************************************************************
  986. InitHeap
  987. *****************************************************************************}
  988. { This function will initialize the Heap manager and need to be called from
  989. the initialization of the system unit }
  990. procedure InitHeap;
  991. begin
  992. FillChar(Blocks^,sizeof(Blocks^),0);
  993. FillChar(NBlocks^,sizeof(NBlocks^),0);
  994. {$ifdef TEMPHEAP}
  995. Curheap:=@baseheap;
  996. Otherheap:=@tempheap;
  997. {$endif TEMPHEAP}
  998. internal_heapsize:=GetHeapSize;
  999. internal_memavail:=internal_heapsize;
  1000. HeapOrg:=GetHeapStart;
  1001. HeapPtr:=HeapOrg;
  1002. HeapEnd:=HeapOrg+internal_memavail;
  1003. HeapError:=@GrowHeap;
  1004. Freelist:=nil;
  1005. end;
  1006. {
  1007. $Log$
  1008. Revision 1.3 1998-10-22 23:50:45 peter
  1009. + check for < 0 which otherwise segfaulted
  1010. Revision 1.2 1998/10/01 14:55:17 peter
  1011. + memorymanager like delphi
  1012. Revision 1.1 1998/09/14 10:48:17 peter
  1013. * FPC_ names
  1014. * Heap manager is now system independent
  1015. Revision 1.18 1998/09/08 15:02:48 peter
  1016. * much more readable :)
  1017. Revision 1.17 1998/09/04 17:27:48 pierre
  1018. * small corrections
  1019. Revision 1.16 1998/08/25 14:15:51 pierre
  1020. * corrected a bug introduced by my last change
  1021. (allocating 1Mb but only using a small part !!)
  1022. Revision 1.15 1998/08/24 14:44:04 pierre
  1023. * bug allocation of more than 1 MB failed corrected
  1024. Revision 1.14 1998/07/30 13:26:21 michael
  1025. + Added support for ErrorProc variable. All internal functions are required
  1026. to call HandleError instead of runerror from now on.
  1027. This is necessary for exception support.
  1028. Revision 1.13 1998/07/02 14:24:09 michael
  1029. Undid carls changes, but renamed _heapsize to internal_heapsize. Make cycle now works
  1030. Revision 1.11 1998/06/25 09:26:10 daniel
  1031. * Removed some more tabs
  1032. Revision 1.10 1998/06/24 11:53:26 daniel
  1033. * Removed some tabs.
  1034. Revision 1.9 1998/06/16 14:55:49 daniel
  1035. * Optimizations
  1036. Revision 1.8 1998/06/15 15:15:13 daniel
  1037. * Brought my policy into practive that the RTL should output only runtime
  1038. errors and no other texts when things go wrong.
  1039. Revision 1.7 1998/05/30 15:01:28 peter
  1040. * this needs also direct mode :(
  1041. Revision 1.6 1998/05/25 10:40:48 peter
  1042. * remake3 works again on tflily
  1043. Revision 1.4 1998/04/21 10:22:48 peter
  1044. + heapblocks
  1045. Revision 1.3 1998/04/09 08:32:14 daniel
  1046. * Optimized some code.
  1047. }