| 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 FreeRTOS 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.
 |