| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 | {    $Id: $    This file is part of the Free Pascal run time library.    Copyright (c) 2004 by Daniel Mantione      member of the Free Pascal development team    Implements a memory manager that makes use of the fact that    a program is running in a virtual address space where pages    can be allocated at random, instead of a more traditional    growing heap.    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. **********************************************************************}unit pagemem;{*****************************************************************************}                                   interface{*****************************************************************************}{*****************************************************************************}                                implementation{*****************************************************************************}{$packrecords 1}{$packenum 1}type    Tpage_type=(pt_8byte_with_bitmap,pt_suballocation,pt_direct_page);        Ppage_type=^Tpage_type;        Pcriterium=^Tcriterium;        Tcriterium=record            criterium1,criterium2:cardinal;        end;        Ptree_struct=^Ttree_struct;        Ttree_struct=record            left,right:ptruint;        end;        {This page layout is targeted at very short strings and linked lists         with very low payload. It uses fixed memory sizes of 8 byte. Memory         overhead should be avoided at all here. An allocation bitmap does this         very well, only 1 bit per memory block.}        Ppage_8byte_with_bitmap=^Tpage_8byte_with_bitmap;        Tpage_8byte_with_bitmap=record            page_type:Tpage_type;            search_index:byte;            free_count:word;            page_birthyear:cardinal;            freelist_prev,freelist_next:Ppage_8byte_with_bitmap;            block_allocation_map:array[0..15] of cardinal;        end;        Ppage_suballocation=^Tpage_suballocation;        Tpage_suballocation=record            page_type:Tpage_type;            reserved:array[1..3] of byte;            page_birthyear:cardinal;        end;        {This page layout is targeted at large memory blocks. We allocate         pages directly from the OS for such blocks.}        Ppage_direct=^Tpage_direct;        Tpage_direct=record            page_type:Tpage_type;            reserved:array[1..3] of byte;            size:cardinal;        end;        Pfree_block=^Tfree_block;        Tfree_block=record            size:cardinal;            tree_sizememloc:Ttree_struct;            tree_memlocation:Ttree_struct;        end;        Tsplay_status=(ts_not_found,ts_found_on_left,                       ts_found_on_p,ts_found_on_right);        Psuballoc_header=^Tsuballoc_header;        Tsuballoc_header=record            alloc_size:ptruint;        end;const   tree_sizememloc_offset=4;        tree_memlocation_offset=12;        page_size=4096;        page_shift=12;        page_mask=$00000fff;        page_8byte_with_bitmap_maxspace=                       (page_size-sizeof(Tpage_8byte_with_bitmap)) div 8;        memblock_align=4;        memblock_alignround=memblock_align-1;        min_suballoc_size=sizeof(Tfree_block);const   freelist_8byte_with_bitmap:Ppage_8byte_with_bitmap=nil;        page_8byte_with_bitmap_init:Tpage_8byte_with_bitmap=           (            page_type:pt_8byte_with_bitmap;            search_index:0;            free_count:page_8byte_with_bitmap_maxspace;            page_birthyear:0;            freelist_prev:nil;            freelist_next:nil;            block_allocation_map:($ffffffff,$ffffffff,$ffffffff,$ffffffff,                                  $ffffffff,$ffffffff,$ffffffff,$ffffffff,                                  $ffffffff,$ffffffff,$ffffffff,$ffffffff,                                  $ffffffff,$ffffffff,$ffffffff,$ffffffff)           );var tree_sizememloc,tree_memlocation:Pfree_block;{****************************************************************************                          Page allocation/deallocation ****************************************************************************} function fpmmap(adr:pointer;len,prot,flags,fd,off:sizeint):pointer;external name 'FPC_SYSC_MMAP';function fpmunmap(adr:pointer;len:sizeint):pointer;external name 'FPC_SYSC_MUNMAP';function geterrno:longint;external name 'FPC_SYS_GETERRNO';const   PROT_READ  = $1;             { page can be read }        PROT_WRITE = $2;             { page can be written }        PROT_EXEC  = $4;             { page can be executed }        PROT_NONE  = $0;             { page can not be accessed }        MAP_SHARED    = $1;          { Share changes }        MAP_PRIVATE   = $2;          { Changes are private }        MAP_TYPE      = $f;          { Mask for type of mapping }        MAP_FIXED     = $10;         { Interpret addr exactly }        MAP_ANONYMOUS = $20;         { don't use a file }        MAP_GROWSDOWN  = $100;       { stack-like segment }        MAP_DENYWRITE  = $800;       { ETXTBSY }        MAP_EXECUTABLE = $1000;      { mark it as an executable }        MAP_LOCKED     = $2000;      { pages are locked }        MAP_NORESERVE  = $4000;      { don't check for reservations }function req_pages(count:cardinal):pointer;{Requests count consecutive pages from the OS.}begin  req_pages:=fpmmap(nil,count shl page_shift,PROT_READ or PROT_WRITE,                    MAP_PRIVATE or MAP_ANONYMOUS,0,0);  if geterrno<>0 then    req_pages:=nil; {This one can fail, so we can handle an out of memory                     situation.}end;procedure sack_pages(p:pointer;count:cardinal);begin  fpmunmap(p,count shl page_shift);  if geterrno<>0 then    runerror(204); {This one should succees.}end;{****************************************************************************                          8-bit bitmap allocated memory ****************************************************************************}procedure new_page_8byte_with_bitmap;var page:Ppage_8byte_with_bitmap;begin  page:=req_pages(1);  page^:=page_8byte_with_bitmap_init;  page^.freelist_next:=freelist_8byte_with_bitmap;  page^.freelist_prev:=nil;  if freelist_8byte_with_bitmap<>nil then    freelist_8byte_with_bitmap^.freelist_prev:=page;  freelist_8byte_with_bitmap:=page;end;function pgetmem_8byte_with_bitmap:pointer;var page:Ppage_8byte_with_bitmap;    bit:cardinal;begin  if freelist_8byte_with_bitmap=nil then    new_page_8byte_with_bitmap;  page:=freelist_8byte_with_bitmap;  with page^ do    begin      {Search a dword in which a bit is set.}      while block_allocation_map[search_index]=0 do        search_index:=(search_index+1) and 15;      ptrint(pgetmem_8byte_with_bitmap):=ptrint(page)+sizeof(page^)+search_index*256;      {Search for a set bit in the dword.}      bit:=1;      while block_allocation_map[search_index] and bit=0 do        begin          bit:=bit shl 1;          inc(ptrint(pgetmem_8byte_with_bitmap),8);        end;      {Allocate the block.}      block_allocation_map[search_index]:=block_allocation_map[search_index] and not bit;      dec(free_count);      if free_count=0 then        begin          {There is no space left in this page. Remove it from the freelist.}          if freelist_next<>nil then            freelist_next^.freelist_prev:=freelist_prev;          if freelist_prev<>nil then            freelist_prev^.freelist_next:=freelist_next;          if freelist_8byte_with_bitmap=page then            freelist_8byte_with_bitmap:=freelist_next;          freelist_prev:=nil;          freelist_next:=nil;        end;    end;end;function pfreemem_8byte_with_bitmap(page:Ppage_8byte_with_bitmap;p:pointer):ptrint;var index,bit:cardinal;begin  index:=(ptrint(p)-ptrint(page)-sizeof(page^)) div 8;  bit:=index and 31;  index:=index shr 5;  with page^ do    begin      if free_count=0 then        begin          {Page will get free slots. Must be included in freelist.}          if freelist_8byte_with_bitmap=nil then            freelist_8byte_with_bitmap:=page          else            begin              freelist_next:=freelist_8byte_with_bitmap;              freelist_8byte_with_bitmap^.freelist_prev:=page;              freelist_8byte_with_bitmap:=page;            end;          {Make sure the next allocation finds the slot without much searching.}           search_index:=index;        end;      block_allocation_map[index]:=block_allocation_map[index] or (1 shl bit);      inc(free_count);      if free_count=page_8byte_with_bitmap_maxspace then        begin          {The page is completely free. It can be returned to the OS, but           remove it from the freelist first.}          if freelist_next<>nil then            freelist_next^.freelist_prev:=freelist_prev;          if freelist_prev<>nil then            freelist_prev^.freelist_next:=freelist_next;          if freelist_8byte_with_bitmap=page then            freelist_8byte_with_bitmap:=freelist_next;          sack_pages(page,1);        end;    end;  pfreemem_8byte_with_bitmap:=8;end;{****************************************************************************                                 Splay tree stuff ****************************************************************************}{ $define debug}{$ifdef debug}procedure write_sizememloc_tree(tree:Pfree_block;level:cardinal);var i:cardinal;begin    if tree=nil then      exit;    write_sizememloc_tree(Pfree_block(tree^.tree_sizememloc.left),level+1);    for i:=1 to level do      write('  ');    writeln(tree^.size,' ',hexstr(ptruint(tree),8));    write_sizememloc_tree(Pfree_block(tree^.tree_sizememloc.right),level+1);end;procedure write_memlocation_tree(tree:Pfree_block;level:cardinal);var i:cardinal;begin    if tree=nil then      exit;    write_memlocation_tree(Pfree_block(tree^.tree_memlocation.left),level+1);    for i:=1 to level do      write('  ');    writeln(hexstr(ptruint(tree),8));    write_memlocation_tree(Pfree_block(tree^.tree_memlocation.right),level+1);end;{$endif}procedure rotate_l(var p:ptruint;offset:cardinal);var p1:ptruint;begin    p1:=Ptree_struct(p+offset)^.right;    Ptree_struct(p+offset)^.right:=Ptree_struct(p1+offset)^.left;    Ptree_struct(p1+offset)^.left:=p;    p:=p1;end;procedure rotate_r(var p:ptruint;offset:cardinal);var p1:ptruint;begin    p1:=Ptree_struct(p+offset)^.left;    Ptree_struct(p+offset)^.left:=Ptree_struct(p1+offset)^.right;    Ptree_struct(p1+offset)^.right:=p;    p:=p1;end;procedure zigzig(var p:ptruint;offset:cardinal);inline;begin    rotate_r(p,offset);    rotate_r(p,offset);end;procedure zigzag(var p:ptruint;offset:cardinal);inline;begin    rotate_l(Ptree_struct(p+offset)^.left,offset);    rotate_r(p,offset);end;procedure zagzig(var p:ptruint;offset:cardinal);inline;begin    rotate_r(Ptree_struct(p+offset)^.right,offset);    rotate_l(p,offset);end;procedure zagzag(var p:ptruint;offset:cardinal);inline;begin    rotate_l(p,offset);    rotate_l(p,offset);end;procedure delete_from_tree(var p:ptruint;offset:cardinal);var p1:ptruint;    pp1:^ptruint;begin  if Ptree_struct(p+offset)^.left=0 then    p:=Ptree_struct(p+offset)^.right  else    begin      if Ptree_struct(p+offset)^.right<>0 then        begin          {Both are occupied. Move right to rightmost leaf of left.}          p1:=Ptree_struct(p+offset)^.left;          repeat            pp1:=@Ptree_struct(p1+offset)^.right;            p1:=pp1^;          until p1=0;          pp1^:=Ptree_struct(p+offset)^.right;        end;      p:=Ptree_struct(p+offset)^.left;    end;end;function find_sizememloc(size:ptruint;var p:Pfree_block):Tsplay_status;begin  find_sizememloc:=ts_found_on_p;  if p=nil then    find_sizememloc:=ts_not_found  else if size<p^.size then {Do nothing if equal...}    case find_sizememloc(size,Pfree_block(p^.tree_sizememloc.left)) of      ts_not_found:        if p^.size<size then          find_sizememloc:=ts_not_found;      ts_found_on_left:        zigzig(ptruint(p),tree_sizememloc_offset);      ts_found_on_p:        find_sizememloc:=ts_found_on_left;      ts_found_on_right:        zigzag(ptruint(p),tree_sizememloc_offset);    end  else if size>p^.size then    case find_sizememloc(size,Pfree_block(p^.tree_sizememloc.right)) of      ts_not_found:        if p^.size<size then          find_sizememloc:=ts_not_found;      ts_found_on_left:        zagzig(ptruint(p),tree_sizememloc_offset);      ts_found_on_p:        find_sizememloc:=ts_found_on_right;      ts_found_on_right:        zagzag(ptruint(p),tree_sizememloc_offset);    end;end;{$if 0}function find_sizememloc(size,loc:ptruint;var p:Pfree_block):Tsplay_status;var on_left:boolean;begin  find_sizememloc:=ts_found_on_p;  if p=nil then    find_sizememloc:=ts_not_found  else    begin      on_left:=size<p^.size;      if size=p^.size then        if loc=ptruint(p) then          exit        else          on_left:=loc<ptruint(p);      if on_left then        case find_sizememloc(size,loc,Pfree_block(p^.tree_sizememloc.left)) of          ts_not_found:            find_sizememloc:=ts_not_found;          ts_found_on_left:            zigzig(ptruint(p),tree_sizememloc_offset);          ts_found_on_p:            find_sizememloc:=ts_found_on_left;          ts_found_on_right:            zigzag(ptruint(p),tree_sizememloc_offset);        end      else        case find_sizememloc(size,loc,Pfree_block(p^.tree_sizememloc.right)) of          ts_not_found:            find_sizememloc:=ts_not_found;          ts_found_on_left:            zagzig(ptruint(p),tree_sizememloc_offset);          ts_found_on_p:            find_sizememloc:=ts_found_on_right;          ts_found_on_right:            zagzag(ptruint(p),tree_sizememloc_offset);        end;    end;end;{$endif}function insert_sizememloc(node:Pfree_block;var p:Pfree_block):Tsplay_status;{Preconditions: node^.size is set node^.tree_sizememloc.left is set to nil node^.tree_sizememloc.right is set to nil}var on_left:boolean;begin  insert_sizememloc:=ts_found_on_p;  if p=nil then    p:=node  else    begin      on_left:=node^.size<p^.size;      if node^.size=p^.size then        on_left:=ptruint(node)<ptruint(p);      if on_left then        case insert_sizememloc(node,Pfree_block(p^.tree_sizememloc.left)) of          ts_found_on_left:            zigzig(ptruint(p),tree_sizememloc_offset);          ts_found_on_p:            insert_sizememloc:=ts_found_on_left;          ts_found_on_right:            zigzag(ptruint(p),tree_sizememloc_offset);        end      else        case insert_sizememloc(node,Pfree_block(p^.tree_sizememloc.right)) of          ts_found_on_left:            zagzig(ptruint(p),tree_sizememloc_offset);          ts_found_on_p:            insert_sizememloc:=ts_found_on_right;          ts_found_on_right:            zagzag(ptruint(p),tree_sizememloc_offset);        end;    end;{$ifdef debug}  writeln('sizememlocboom na insert');  write_sizememloc_tree(tree_sizememloc,1);{$endif}end;{$if 0}function find_memlocation(location:ptruint;var p:Pfree_block;                          find_smaller:boolean):Tsplay_status;begin  find_memlocation:=ts_found_on_p;  if p=nil then    find_memlocation:=ts_not_found  else if location<ptruint(p) then {Do nothing if equal...}    case find_memlocation(location,Pfree_block(p^.tree_memlocation.left),                          find_smaller) of      ts_not_found:        if (ptruint(p)>location) or not find_smaller then          find_memlocation:=ts_not_found;      ts_found_on_left:        zigzig(ptruint(p),tree_memlocation_offset);      ts_found_on_p:        find_memlocation:=ts_found_on_left;      ts_found_on_right:        zigzag(ptruint(p),tree_memlocation_offset);    end  else if location>ptruint(p) then    case find_memlocation(location,Pfree_block(p^.tree_memlocation.right),                          find_smaller) of      ts_not_found:        if (ptruint(p)>location) or not find_smaller then          find_memlocation:=ts_not_found;      ts_found_on_left:        zagzig(ptruint(p),tree_memlocation_offset);      ts_found_on_p:        find_memlocation:=ts_found_on_right;      ts_found_on_right:        zagzag(ptruint(p),tree_memlocation_offset);    end;end;{$endif}function insert_memlocation(node:Pfree_block;var p:Pfree_block):Tsplay_status;{Preconditions: node^.size is set node^.tree_sizememloc.left is set to nil node^.tree_sizememloc.right is set to nil}begin  insert_memlocation:=ts_found_on_p;  if p=nil then    p:=node  else if ptruint(node)<=ptruint(p) then {Equal? Insert on left.}    case insert_memlocation(node,Pfree_block(p^.tree_memlocation.left)) of      ts_found_on_left:        zigzig(ptruint(p),tree_memlocation_offset);      ts_found_on_p:        insert_memlocation:=ts_found_on_left;      ts_found_on_right:        zigzag(ptruint(p),tree_memlocation_offset);    end  else if ptruint(node)>ptruint(p) then    case insert_memlocation(node,Pfree_block(p^.tree_memlocation.right)) of      ts_found_on_left:        zagzig(ptruint(p),tree_memlocation_offset);      ts_found_on_p:        insert_memlocation:=ts_found_on_right;      ts_found_on_right:        zagzag(ptruint(p),tree_memlocation_offset);    end;{$ifdef debug}    writeln('memlocationboom na insert');    write_memlocation_tree(tree_memlocation,1);{$endif}end;function get_memlocation(node:Pfree_block):Pfree_block;{Iteratively delete node from tree without splaying.}var p:^Pfree_block;begin  p:=@tree_memlocation;  while (p^<>nil) and (p^<>node) do    if ptruint(node)<ptruint(p^) then      p:=@p^^.tree_memlocation.left    else      p:=@p^^.tree_memlocation.right;  get_memlocation:=p^;  if p^<>nil then    delete_from_tree(ptruint(p^),tree_memlocation_offset);end;function get_sizememloc(node:Pfree_block):Pfree_block;{Iteratively delete node from tree without splaying.}var p:^Pfree_block;    on_left:boolean;begin  p:=@tree_sizememloc;  while (p^<>nil) and (p^<>node) do    begin      on_left:=node^.size<p^^.size;      if node^.size=p^^.size then        on_left:=ptruint(node)<ptruint(p^);      if on_left then        p:=@p^^.tree_sizememloc.left      else        p:=@p^^.tree_sizememloc.right;    end;  get_sizememloc:=p^;  if p^<>nil then    delete_from_tree(ptruint(p^),tree_sizememloc_offset);end;function get_block_by_size(size:cardinal):Pfree_block;var what:^ptruint;begin  case find_sizememloc(size,tree_sizememloc) of    ts_not_found:      begin        get_block_by_size:=nil;        exit;      end;    ts_found_on_left:      what:=@tree_sizememloc^.tree_sizememloc.left;    ts_found_on_p:      what:=@tree_sizememloc;    ts_found_on_right:      what:=@tree_sizememloc^.tree_sizememloc.right;  end;  get_block_by_size:=Pfree_block(what^);  delete_from_tree(what^,tree_sizememloc_offset);  if get_memlocation(get_block_by_size)=nil then    runerror(204);end;function get_block_by_memlocation(location:ptruint):Pfree_block;var what:^ptruint;begin  get_block_by_memlocation:=get_memlocation(Pfree_block(location));  if get_block_by_memlocation<>nil then    begin      get_sizememloc(get_block_by_memlocation);{      case find_sizememloc(get_block_by_memlocation^.size,                           ptruint(get_block_by_memlocation),tree_sizememloc) of        ts_not_found:          runerror(204);        ts_found_on_left:          what:=@tree_sizememloc^.tree_sizememloc.left;        ts_found_on_p:          what:=@tree_sizememloc;        ts_found_on_right:          what:=@tree_sizememloc^.tree_sizememloc.right;      end;      delete_from_tree(what^,tree_sizememloc_offset);}    end;end;function get_smaller_neighbour(location:ptruint):Pfree_block;var p,what:^ptruint;begin  {Find a smaller block. Don't splay as it will be deleted.}  p:=@tree_memlocation;  what:=nil;  while (p^<>0) do    if location<=p^ then      p:=@Pfree_block(p^)^.tree_memlocation.left    else      begin        what:=p;        p:=@Pfree_block(p^)^.tree_memlocation.right;      end;  if (what=nil) or (ptruint(what^)+Pfree_block(what^)^.size<>location) then    begin      get_smaller_neighbour:=nil;      exit;    end;  get_smaller_neighbour:=Pfree_block(what^);  delete_from_tree(ptruint(what^),tree_memlocation_offset);  get_sizememloc(get_smaller_neighbour);end;{function pgetmem_directpage(memsize:ptrint):pointer;var npages:ptrint;begin  npages:=(memsize+sizeof(Tpage_direct)+page_size-1) div page_size;  pgetmem_directpage:=req_pages(npages);  with Ppage_direct(pgetmem_directpage)^ do    begin      page_type:=pt_direct_page;      size:=memsize;    end;end;}function pgetmem_suballocpage(memsize:ptrint):pointer;var free_block:Pfree_block;    page:pointer;    needsize,remaining,block_start:ptruint;begin{$ifdef debug}  writeln('-------Getmem------- ',memsize);{$endif}  {Constant parts on left because of constant evaluation.}  needsize:=(sizeof(Tsuballoc_header)+memblock_alignround+memsize) and not memblock_alignround;  if needsize<min_suballoc_size then    needsize:=min_suballoc_size;{$ifdef debug}  writeln('sizememlocboom voor get:');  write_sizememloc_tree(tree_sizememloc,2);{$endif}  free_block:=get_block_by_size(needsize);  if free_block=nil then    begin      page:=req_pages(1);      Ppage_suballocation(page)^.page_type:=pt_suballocation;      {Allocate at the end of the page, a free block at the start.}      free_block:=Pfree_block(ptruint(page)+sizeof(Tpage_suballocation));      remaining:=page_size-needsize-sizeof(Tpage_suballocation);      block_start:=ptruint(page)+page_size-needsize;      Psuballoc_header(block_start)^.alloc_size:=needsize;      pgetmem_suballocpage:=pointer(block_start+sizeof(Tsuballoc_header));    end  else    begin      block_start:=ptruint(free_block);      remaining:=free_block^.size-needsize;      if (remaining<min_suballoc_size) then        begin          needsize:=free_block^.size;          free_block:=nil;        end      else        inc(ptruint(free_block),needsize);      Psuballoc_header(block_start)^.alloc_size:=needsize;      pgetmem_suballocpage:=pointer(block_start+sizeof(Tsuballoc_header));    end;  if free_block<>nil then    begin      with free_block^ do        begin          size:=remaining;          tree_sizememloc.left:=0;          tree_sizememloc.right:=0;          tree_memlocation.left:=0;          tree_memlocation.right:=0;        end;      insert_sizememloc(free_block,tree_sizememloc);      insert_memlocation(free_block,tree_memlocation);    end;end;function pfreemem_suballoc_page(page:Ppage_direct;p:pointer):ptrint;var free_block,neighbour:Pfree_block;    headerp:Psuballoc_header;    asize:ptruint;begin{$Ifdef debug}  write('-------Freemem------- ');{$endif}  headerp:=Psuballoc_header(ptrint(p)-sizeof(Tsuballoc_header));  asize:=headerp^.alloc_size;{$ifdef debug}  writeln(hexstr(ptruint(page),8),' ',asize);{$endif}  free_block:=Pfree_block(headerp);  {Search neighbour to coalesce with above block.}  neighbour:=get_block_by_memlocation(ptruint(free_block)+asize);  if neighbour<>nil then    inc(asize,neighbour^.size);  {Search neighbour to coalesce with below block.}  neighbour:=get_smaller_neighbour(ptruint(free_block));  if neighbour<>nil then    begin      inc(asize,neighbour^.size);      free_block:=neighbour;    end;  {Page empty??}  if (ptruint(free_block) and page_mask=sizeof(Tpage_suballocation)) and     (asize=page_size-sizeof(Tpage_suballocation)) then    sack_pages(pointer(ptruint(free_block) and not page_mask),1)  else    begin      with free_block^ do        begin          size:=asize;          tree_sizememloc.left:=0;          tree_sizememloc.right:=0;          tree_memlocation.left:=0;          tree_memlocation.right:=0;        end;      insert_sizememloc(free_block,tree_sizememloc);      insert_memlocation(free_block,tree_memlocation);    end;end;function pgetmem(size:ptrint):pointer;begin  if size<=8 then    pgetmem:=pgetmem_8byte_with_bitmap  else    pgetmem:=pgetmem_suballocpage(size);end;function pallocmem(size:ptrint):pointer;begin  if size<=8 then    begin      pallocmem:=pgetmem_8byte_with_bitmap;      fillchar(Pbyte(pallocmem)^,8,0);    end  else    {Freshly allocated pages are allways already cleared.}{    pgallocmem:=pgallocmem_directpage(size)};end;function pfreemem(p:pointer):ptrint;var page:pointer;begin  page:=pointer(ptrint(p) and not page_mask);  case Ppage_type(page)^ of    pt_8byte_with_bitmap:      pfreemem:=pfreemem_8byte_with_bitmap(page,p);    pt_suballocation:      pfreemem:=pfreemem_suballoc_page(page,p);  else    runerror(204);  end;end;function pfreememsize(p:pointer;size:ptrint):ptrint;begin{  runerror(204);}  pfreemem(p);end;function preallocmem(var p:pointer;size:ptrint):pointer;begin  runerror(204);end;function pmemsize(p:pointer):ptrint;begin  runerror(204);end;const page_memory_manager:Tmemorymanager=    (      needlock:false;      getmem:@pgetmem;      freemem:@pfreemem;      freememsize:@pfreememsize;      allocmem:@pallocmem;      reallocmem:@preallocmem;      memsize:@pmemsize;{      memavail:@pmemavail;}{      maxavail:@pmaxavail;}{      heapsize:@pheapsize;}    );var oldmemman:Tmemorymanager;initialization  getmemorymanager(oldmemman);  setmemorymanager(page_memory_manager);finalization  setmemorymanager(oldmemman);end.
 |