FPPS4/sys/kern/kern_mtxpool.pas

159 lines
4.0 KiB
Plaintext

unit kern_mtxpool;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
kern_mtx;
const
{ Pool sizes must be a power of two }
MTX_POOL_LOCKBUILDER_SIZE=128;
MTX_POOL_SLEEP_SIZE =128;
type
mtxpool_header=packed record
mtxpool_size :Integer;
mtxpool_mask :Integer;
mtxpool_shift:Integer;
mtxpool_next :Integer;
end;
pp_mtx_pool=^p_mtx_pool;
p_mtx_pool=^mtx_pool;
mtx_pool=packed object
mtx_pool_header:mtxpool_header;
mtx_pool_ary :array[0..0] of mtx;
property mtx_pool_size :Integer read mtx_pool_header.mtxpool_size write mtx_pool_header.mtxpool_size ;
property mtx_pool_mask :Integer read mtx_pool_header.mtxpool_mask write mtx_pool_header.mtxpool_mask ;
property mtx_pool_shift:Integer read mtx_pool_header.mtxpool_shift write mtx_pool_header.mtxpool_shift;
property mtx_pool_next :Integer read mtx_pool_header.mtxpool_next write mtx_pool_header.mtxpool_next ;
end;
mtx_pool_lockbuilder=packed record
mtx_pool_header:mtxpool_header;
mtx_pool_ary :array[0..MTX_POOL_LOCKBUILDER_SIZE-1] of mtx;
end;
function mtx_pool_find(pool:p_mtx_pool;ptr:Pointer):p_mtx;
procedure mtx_pool_initialize(pool:p_mtx_pool;mtx_name:PChar;pool_size:Integer);
function mtx_pool_create(mtx_name:PChar;pool_size:Integer):p_mtx_pool;
procedure mtx_pool_destroy(poolp:pp_mtx_pool);
function mtx_pool_alloc(pool:p_mtx_pool):p_mtx;
procedure mtx_pool_setup_dynamic(); //SYSINIT(mtxpooli2, SI_SUB_MTX_POOL_DYNAMIC, SI_ORDER_FIRST, mtx_pool_setup_dynamic, NULL);
var
mtxpool_sleep:p_mtx_pool;
implementation
const
POINTER_BITS =64;
HASH_MULTIPLIER=11400714819323198485; { (2^64)*(sqrt(5)-1)/2 }
{
* Exitthe (shared) pool mutex associated with the specified address.
* The returned mutex is a leaf level mutex, meaning that if you obtain it
* you cannot obtain any other mutexes until you release it. You can
* legally msleep() on the mutex.
}
function mtx_pool_find(pool:p_mtx_pool;ptr:Pointer):p_mtx;
var
p:Integer;
begin
Assert(pool<>nil, ('_mtx_pool_find(): nil pool'));
{
* Fibonacci hash, see Knuth's
* _Art of Computer Programming, Volume 3 / Sorting and Searching_
}
p:=((HASH_MULTIPLIER * ptruint(ptr)) shr pool^.mtx_pool_shift) and pool^.mtx_pool_mask;
Exit(@pool^.mtx_pool_ary[p]);
end;
procedure mtx_pool_initialize(pool:p_mtx_pool;mtx_name:PChar;pool_size:Integer);
var
i,maskbits:Integer;
begin
pool^.mtx_pool_size:=pool_size;
pool^.mtx_pool_mask:=pool_size - 1;
i:=1;
maskbits:=0;
while ((i and pool_size)=0) do
begin
Inc(maskbits);
i:=i shl 1;
end;
pool^.mtx_pool_shift:=POINTER_BITS - maskbits;
pool^.mtx_pool_next:=0;
For i:=0 to pool_size-1 do
mtx_init(pool^.mtx_pool_ary[i], mtx_name);
end;
function powerof2(i:DWord):Boolean; inline;
begin
Result:=popcnt(i)=1;
end;
function mtx_pool_create(mtx_name:PChar;pool_size:Integer):p_mtx_pool;
var
pool:p_mtx_pool;
begin
if (pool_size <= 0) or (not powerof2(pool_size)) then
begin
Writeln('WARNING: %s pool size is not a power of 2.', mtx_name);
pool_size:=128;
end;
pool:=AllocMem(sizeof(mtx_pool)+
((pool_size - 1) * sizeof(mtx))
);
mtx_pool_initialize(pool, mtx_name, pool_size);
Exit(pool);
end;
procedure mtx_pool_destroy(poolp:pp_mtx_pool);
var
i:Integer;
pool:p_mtx_pool;
begin
pool:=poolp^;
For i:=(pool^.mtx_pool_size-1) downto 0 do
begin
mtx_destroy(pool^.mtx_pool_ary[i]);
end;
FreeMem(pool);
poolp^:=nil;
end;
{
* Obtain a (shared) mutex from the pool. The returned mutex is a leaf
* level mutex, meaning that if you obtain it you cannot obtain any other
* mutexes until you release it. You can legally msleep() on the mutex.
}
function mtx_pool_alloc(pool:p_mtx_pool):p_mtx;
var
i:Integer;
begin
Assert(pool<>nil, ('mtx_pool_alloc(): nil pool'));
{
* mtx_pool_next is unprotected against multiple accesses,
* but simultaneous access by two CPUs should not be very
* harmful.
}
i:=pool^.mtx_pool_next;
pool^.mtx_pool_next:=(i + 1) and pool^.mtx_pool_mask;
Exit(@pool^.mtx_pool_ary[i]);
end;
procedure mtx_pool_setup_dynamic();
begin
mtxpool_sleep:=mtx_pool_create('sleep mtxpool',MTX_POOL_SLEEP_SIZE);
end;
end.