heapmgr.pp 7.7 KB

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