123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2011 by the Free Pascal development team.
- Tiny heap manager for the FPC embedded target
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$modeswitch result}
- Unit heapmgr;
- interface
- procedure RegisterHeapBlock(AAddress: pointer; ASize: ptruint);
-
- function GetAlignedMem(Size, Alignment: ptruint): pointer;
- implementation
- const
- MinBlock = 16;
- type
- PHeapBlock = ^THeapBlock;
- THeapBlock = record
- Size: ptruint;
- Next: PHeapBlock;
- EndAddr: pointer;
- end;
- var
- Blocks: PHeapBlock = nil;
- procedure InternalFreeMem(Addr: Pointer; Size: ptruint); forward;
- function FindSize(p: pointer): ptruint; inline;
- begin
- FindSize := PPtrUInt(p)[-1];
- end;
- function SysGetMem(Size: ptruint): pointer;
- var
- p, prev: PHeapBlock;
- AllocSize, RestSize: ptruint;
- begin
- if size+sizeof(PtrUInt)<MinBlock then
- AllocSize := MinBlock
- else
- AllocSize := align(size+sizeof(PtrUInt), sizeof(pointer));
- p := Blocks;
- prev := nil;
- while assigned(p) and (p^.Size < AllocSize) do
- begin
- prev := p;
- p := p^.Next;
- end;
- if assigned(p) then
- begin
- result := @pptruint(p)[1];
- if (p^.size > AllocSize) and
- (p^.Size-AllocSize >= MinBlock) then
- RestSize := p^.Size-AllocSize
- else
- begin
- AllocSize := p^.Size;
- RestSize := 0;
- end;
- if prev = nil then
- Blocks := p^.Next
- else
- prev^.next := p^.next;
- pptruint(p)^ := size;
- InternalFreemem(pointer(ptruint(p)+AllocSize), RestSize);
- end
- else
- begin
- if ReturnNilIfGrowHeapFails then
- Result := nil
- else
- RunError(203);
- end;
- end;
- function GetAlignedMem(Size, Alignment: ptruint): pointer;
- var
- mem: Pointer;
- memp: ptruint;
- begin
- if alignment <= sizeof(pointer) then
- result := GetMem(size)
- else
- begin
- mem := GetMem(Size+Alignment-1+MinBlock);
- memp := align(ptruint(mem)+MinBlock, Alignment);
- InternalFreemem(mem, ptruint(memp)-ptruint(mem));
- result := pointer(memp);
- end;
- end;
- procedure InternalFreeMem(Addr: Pointer; Size: ptruint);
- var
- b, p, prev: PHeapBlock;
- concatenated: boolean;
- begin
- if size<=0 then
- exit;
- concatenated := true;
- while concatenated do
- begin
- concatenated := false;
- b := addr;
- b^.Next := Blocks;
- b^.Size := Size;
- b^.EndAddr := pointer(ptruint(addr)+size);
- if Blocks = nil then
- Blocks := b
- else
- begin
- p := Blocks;
- prev := nil;
- while assigned(p) do
- begin
- if p^.EndAddr = addr then
- begin
- addr:=p;
- size:=p^.size+size;
- if prev = nil then
- blocks:=p^.next
- else
- prev^.next:=p^.next;
- concatenated:=true;
- break;
- end
- else if p = b^.EndAddr then
- begin
- size:=p^.size+size;
- if prev = nil then
- blocks:=p^.next
- else
- prev^.next:=p^.next;
- concatenated:=true;
- break;
- end;
- prev := p;
- p := p^.next;
- end;
- if not concatenated then
- begin
- p := Blocks;
- prev := nil;
- while assigned(p) and (p^.Size < size) do
- begin
- prev := p;
- p := p^.Next;
- end;
- if assigned(prev) then
- begin
- b^.Next := p;
- prev^.Next := b;
- end
- else
- Blocks := b;
- end;
- end;
- end;
- end;
- function SysFreeMem(Addr: Pointer): ptruint;
- var
- sz: ptruint;
- begin
- if addr=nil then
- begin
- result:=0;
- exit;
- end;
- sz := Align(FindSize(addr)+SizeOf(pointer), sizeof(pointer));
- if sz < MinBlock then
- sz := MinBlock;
- InternalFreeMem(@pptruint(addr)[-1], sz);
- result := sz;
- end;
- function SysFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
- begin
- result := SysFreeMem(addr);
- end;
- function SysMemSize(p: pointer): ptruint;
- begin
- result := findsize(p);
- end;
- function SysAllocMem(size: ptruint): pointer;
- begin
- result := SysGetMem(size);
- if result<>nil then
- FillChar(pbyte(result)^,size,0);
- end;
- function SysReAllocMem(var p: pointer; size: ptruint):pointer;
- var
- sz: ptruint;
- begin
- if size=0 then
- begin
- SysFreeMem(p);
- result := nil;
- p := nil;
- end
- else if p=nil then
- begin
- result := AllocMem(size);
- p := result;
- end
- else
- begin
- result := AllocMem(size);
- if result <> nil then
- begin
- if p <> nil then
- begin
- sz := FindSize(p);
- if sz > size then
- sz := size;
- move(pbyte(p)^, pbyte(result)^, sz);
- end;
- end;
- SysFreeMem(p);
- p := result;
- end;
- end;
- procedure RegisterHeapBlock(AAddress: pointer; ASize: ptruint);
- begin
- InternalFreeMem(AAddress, ASize);
- end;
- { avoid that programs crash due to a heap status request }
- function SysGetFPCHeapStatus : TFPCHeapStatus;
- begin
- FillChar(Result,SizeOf(Result),0);
- end;
- { avoid that programs crash due to a heap status request }
- function SysGetHeapStatus : THeapStatus;
- begin
- FillChar(Result,SizeOf(Result),0);
- end;
- const
- MyMemoryManager: TMemoryManager = (
- NeedLock: false; // Obsolete
- GetMem: @SysGetMem;
- FreeMem: @SysFreeMem;
- FreeMemSize: @SysFreeMemSize;
- AllocMem: @SysAllocMem;
- ReAllocMem: @SysReAllocMem;
- MemSize: @SysMemSize;
- InitThread: nil;
- DoneThread: nil;
- RelocateHeap: nil;
- GetHeapStatus: @SysGetHeapStatus;
- GetFPCHeapStatus: @SysGetFPCHeapStatus;
- );
- var
- initialheap : record end; external name '__fpc_initialheap';
- heapsize : PtrInt; external name '__heapsize';
- initialization
- SetMemoryManager(MyMemoryManager);
- RegisterHeapBlock(@initialheap,heapsize);
- finalization
- //FinalizeHeap;
- end.
|