heapmgr.pp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2011 by the Free Pascal development team.
  4. Tiny heap manager for the FPC embedded target
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$modeswitch result}
  12. Unit heapmgr;
  13. interface
  14. procedure RegisterHeapBlock(AAddress: pointer; ASize: ptruint);
  15. function GetAlignedMem(Size, Alignment: ptruint): pointer;
  16. implementation
  17. const
  18. MinBlock = 16;
  19. type
  20. PHeapBlock = ^THeapBlock;
  21. THeapBlock = record
  22. Size: ptruint;
  23. Next: PHeapBlock;
  24. EndAddr: pointer;
  25. end;
  26. var
  27. Blocks: PHeapBlock = nil;
  28. procedure InternalFreeMem(Addr: Pointer; Size: ptruint); forward;
  29. function FindSize(p: pointer): ptruint; inline;
  30. begin
  31. FindSize := PPtrUInt(p)[-1];
  32. end;
  33. function SysGetMem(Size: ptruint): pointer;
  34. var
  35. p, prev: PHeapBlock;
  36. AllocSize, RestSize: ptruint;
  37. begin
  38. if size+sizeof(PtrUInt)<MinBlock then
  39. AllocSize := MinBlock
  40. else
  41. AllocSize := align(size+sizeof(PtrUInt), sizeof(pointer));
  42. p := Blocks;
  43. prev := nil;
  44. while assigned(p) and (p^.Size < AllocSize) do
  45. begin
  46. prev := p;
  47. p := p^.Next;
  48. end;
  49. if assigned(p) then
  50. begin
  51. result := @pptruint(p)[1];
  52. if (p^.size > AllocSize) and
  53. (p^.Size-AllocSize >= MinBlock) then
  54. RestSize := p^.Size-AllocSize
  55. else
  56. begin
  57. AllocSize := p^.Size;
  58. RestSize := 0;
  59. end;
  60. if prev = nil then
  61. Blocks := p^.Next
  62. else
  63. prev^.next := p^.next;
  64. pptruint(p)^ := size;
  65. InternalFreemem(pointer(ptruint(p)+AllocSize), RestSize);
  66. end
  67. else
  68. begin
  69. if ReturnNilIfGrowHeapFails then
  70. Result := nil
  71. else
  72. RunError(203);
  73. end;
  74. end;
  75. function GetAlignedMem(Size, Alignment: ptruint): pointer;
  76. var
  77. mem: Pointer;
  78. memp: ptruint;
  79. begin
  80. if alignment <= sizeof(pointer) then
  81. result := GetMem(size)
  82. else
  83. begin
  84. mem := GetMem(Size+Alignment-1+MinBlock);
  85. memp := align(ptruint(mem)+MinBlock, Alignment);
  86. InternalFreemem(mem, ptruint(memp)-ptruint(mem));
  87. result := pointer(memp);
  88. end;
  89. end;
  90. procedure InternalFreeMem(Addr: Pointer; Size: ptruint);
  91. var
  92. b, p, prev: PHeapBlock;
  93. concatenated: boolean;
  94. begin
  95. if size<=0 then
  96. exit;
  97. concatenated := true;
  98. while concatenated do
  99. begin
  100. concatenated := false;
  101. b := addr;
  102. b^.Next := Blocks;
  103. b^.Size := Size;
  104. b^.EndAddr := pointer(ptruint(addr)+size);
  105. if Blocks = nil then
  106. Blocks := b
  107. else
  108. begin
  109. p := Blocks;
  110. prev := nil;
  111. while assigned(p) do
  112. begin
  113. if p^.EndAddr = addr then
  114. begin
  115. addr:=p;
  116. size:=p^.size+size;
  117. if prev = nil then
  118. blocks:=p^.next
  119. else
  120. prev^.next:=p^.next;
  121. concatenated:=true;
  122. break;
  123. end
  124. else if p = b^.EndAddr then
  125. begin
  126. size:=p^.size+size;
  127. if prev = nil then
  128. blocks:=p^.next
  129. else
  130. prev^.next:=p^.next;
  131. concatenated:=true;
  132. break;
  133. end;
  134. prev := p;
  135. p := p^.next;
  136. end;
  137. if not concatenated then
  138. begin
  139. p := Blocks;
  140. prev := nil;
  141. while assigned(p) and (p^.Size < size) do
  142. begin
  143. prev := p;
  144. p := p^.Next;
  145. end;
  146. if assigned(prev) then
  147. begin
  148. b^.Next := p;
  149. prev^.Next := b;
  150. end
  151. else
  152. Blocks := b;
  153. end;
  154. end;
  155. end;
  156. end;
  157. function SysFreeMem(Addr: Pointer): ptruint;
  158. var
  159. sz: ptruint;
  160. begin
  161. if addr=nil then
  162. begin
  163. result:=0;
  164. exit;
  165. end;
  166. sz := Align(FindSize(addr)+SizeOf(pointer), sizeof(pointer));
  167. InternalFreeMem(@pptruint(addr)[-1], sz);
  168. result := sz;
  169. end;
  170. function SysFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  171. begin
  172. result := SysFreeMem(addr);
  173. end;
  174. function SysMemSize(p: pointer): ptruint;
  175. begin
  176. result := findsize(p);
  177. end;
  178. function SysAllocMem(size: ptruint): pointer;
  179. begin
  180. result := SysGetMem(size);
  181. if result<>nil then
  182. FillChar(pbyte(result)^,size,0);
  183. end;
  184. function SysReAllocMem(var p: pointer; size: ptruint):pointer;
  185. var
  186. sz: ptruint;
  187. begin
  188. if size=0 then
  189. begin
  190. SysFreeMem(p);
  191. result := nil;
  192. p := nil;
  193. end
  194. else if p=nil then
  195. begin
  196. result := AllocMem(size);
  197. p := result;
  198. end
  199. else
  200. begin
  201. result := AllocMem(size);
  202. if result <> nil then
  203. begin
  204. if p <> nil then
  205. begin
  206. sz := FindSize(p);
  207. if sz > size then
  208. sz := size;
  209. move(pbyte(p)^, pbyte(result)^, sz);
  210. end;
  211. end;
  212. SysFreeMem(p);
  213. p := result;
  214. end;
  215. end;
  216. procedure RegisterHeapBlock(AAddress: pointer; ASize: ptruint);
  217. begin
  218. InternalFreeMem(AAddress, ASize);
  219. end;
  220. { avoid that programs crash due to a heap status request }
  221. function SysGetFPCHeapStatus : TFPCHeapStatus;
  222. begin
  223. FillChar(Result,SizeOf(Result),0);
  224. end;
  225. { avoid that programs crash due to a heap status request }
  226. function SysGetHeapStatus : THeapStatus;
  227. begin
  228. FillChar(Result,SizeOf(Result),0);
  229. end;
  230. const
  231. MyMemoryManager: TMemoryManager = (
  232. NeedLock: false; // Obsolete
  233. GetMem: @SysGetMem;
  234. FreeMem: @SysFreeMem;
  235. FreeMemSize: @SysFreeMemSize;
  236. AllocMem: @SysAllocMem;
  237. ReAllocMem: @SysReAllocMem;
  238. MemSize: @SysMemSize;
  239. InitThread: nil;
  240. DoneThread: nil;
  241. RelocateHeap: nil;
  242. GetHeapStatus: @SysGetHeapStatus;
  243. GetFPCHeapStatus: @SysGetFPCHeapStatus;
  244. );
  245. var
  246. initialheap : record end; external name '__fpc_initialheap';
  247. heapsize : PtrInt; external name '__heapsize';
  248. initialization
  249. SetMemoryManager(MyMemoryManager);
  250. RegisterHeapBlock(@initialheap,heapsize);
  251. finalization
  252. //FinalizeHeap;
  253. end.