mirror of https://github.com/red-prig/fpPS4.git
159 lines
4.0 KiB
Plaintext
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.
|
|
|