heapmgr.pp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. if sz < MinBlock then
  168. sz := MinBlock;
  169. InternalFreeMem(@pptruint(addr)[-1], sz);
  170. result := sz;
  171. end;
  172. function SysFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  173. begin
  174. result := SysFreeMem(addr);
  175. end;
  176. function SysMemSize(p: pointer): ptruint;
  177. begin
  178. result := findsize(p);
  179. end;
  180. function SysAllocMem(size: ptruint): pointer;
  181. begin
  182. result := SysGetMem(size);
  183. if result<>nil then
  184. FillChar(pbyte(result)^,size,0);
  185. end;
  186. function SysReAllocMem(var p: pointer; size: ptruint):pointer;
  187. var
  188. sz: ptruint;
  189. begin
  190. if size=0 then
  191. begin
  192. SysFreeMem(p);
  193. result := nil;
  194. p := nil;
  195. end
  196. else if p=nil then
  197. begin
  198. result := AllocMem(size);
  199. p := result;
  200. end
  201. else
  202. begin
  203. result := AllocMem(size);
  204. if result <> nil then
  205. begin
  206. if p <> nil then
  207. begin
  208. sz := FindSize(p);
  209. if sz > size then
  210. sz := size;
  211. move(pbyte(p)^, pbyte(result)^, sz);
  212. end;
  213. end;
  214. SysFreeMem(p);
  215. p := result;
  216. end;
  217. end;
  218. procedure RegisterHeapBlock(AAddress: pointer; ASize: ptruint);
  219. begin
  220. InternalFreeMem(AAddress, ASize);
  221. end;
  222. { avoid that programs crash due to a heap status request }
  223. function SysGetFPCHeapStatus : TFPCHeapStatus;
  224. begin
  225. FillChar(Result,SizeOf(Result),0);
  226. end;
  227. { avoid that programs crash due to a heap status request }
  228. function SysGetHeapStatus : THeapStatus;
  229. begin
  230. FillChar(Result,SizeOf(Result),0);
  231. end;
  232. const
  233. MyMemoryManager: TMemoryManager = (
  234. NeedLock: false; // Obsolete
  235. GetMem: @SysGetMem;
  236. FreeMem: @SysFreeMem;
  237. FreeMemSize: @SysFreeMemSize;
  238. AllocMem: @SysAllocMem;
  239. ReAllocMem: @SysReAllocMem;
  240. MemSize: @SysMemSize;
  241. InitThread: nil;
  242. DoneThread: nil;
  243. RelocateHeap: nil;
  244. GetHeapStatus: @SysGetHeapStatus;
  245. GetFPCHeapStatus: @SysGetFPCHeapStatus;
  246. );
  247. var
  248. initialheap : record end; external name '__fpc_initialheap';
  249. heapsize : PtrInt; external name '__heapsize';
  250. initialization
  251. SetMemoryManager(MyMemoryManager);
  252. RegisterHeapBlock(@initialheap,heapsize);
  253. finalization
  254. //FinalizeHeap;
  255. end.