heapmgr.pp 7.2 KB

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