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.