|
@@ -0,0 +1,887 @@
|
|
|
+{
|
|
|
+ $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.
|
|
|
+
|
|
|
+{
|
|
|
+ $Log: $
|
|
|
+}
|