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