mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-17 03:19:33 +02:00
* Fix tabs
git-svn-id: trunk@135 -
This commit is contained in:
parent
aea6563bba
commit
a7d57f0268
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -3544,6 +3544,7 @@ rtl/inc/mvecimp.inc svneol=native#text/plain
|
||||
rtl/inc/objects.pp svneol=native#text/plain
|
||||
rtl/inc/objpas.inc svneol=native#text/plain
|
||||
rtl/inc/objpash.inc svneol=native#text/plain
|
||||
rtl/inc/pagemem.pp svneol=native#text/plain
|
||||
rtl/inc/printer.inc svneol=native#text/plain
|
||||
rtl/inc/printerh.inc svneol=native#text/plain
|
||||
rtl/inc/readme -text
|
||||
|
887
rtl/inc/pagemem.pp
Normal file
887
rtl/inc/pagemem.pp
Normal file
@ -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: $
|
||||
}
|
Loading…
Reference in New Issue
Block a user