mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-27 00:20:36 +00:00
308 lines
5.5 KiB
ObjectPascal
308 lines
5.5 KiB
ObjectPascal
unit spinlock;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
type
|
|
backoff_exp=object
|
|
private
|
|
Const
|
|
lower_bound = 16; ///< Minimum spinning limit
|
|
upper_bound = 16*1024; ///< Maximum spinning limit
|
|
Var
|
|
m_nExpCur:SizeUInt; //=lower_bound
|
|
public
|
|
Procedure Wait;
|
|
Procedure Reset;
|
|
end;
|
|
|
|
r_spin_lock=record
|
|
_lock:DWORD;
|
|
count:DWORD;
|
|
owner:DWORD;
|
|
end;
|
|
|
|
function spin_trylock(Var P:Pointer):Boolean;
|
|
function spin_trylock(Var P:SizeUint):Boolean;
|
|
{$IF defined(CPUX86_64)}
|
|
function spin_trylock(Var P:DWORD):Boolean;
|
|
{$ENDIF}
|
|
function spin_tryunlock(Var P:Pointer):Boolean;
|
|
function spin_tryunlock(Var P:SizeUint):Boolean;
|
|
{$IF defined(CPUX86_64)}
|
|
function spin_tryunlock(Var P:DWORD):Boolean;
|
|
{$ENDIF}
|
|
procedure spin_lock(Var P:Pointer);
|
|
procedure spin_lock(Var P:SizeUint);
|
|
{$IF defined(CPUX86_64)}
|
|
procedure spin_lock(Var P:DWORD);
|
|
{$ENDIF}
|
|
procedure spin_unlock(Var P:Pointer);
|
|
procedure spin_unlock(Var P:SizeUint);
|
|
{$IF defined(CPUX86_64)}
|
|
procedure spin_unlock(Var P:DWORD);
|
|
{$ENDIF}
|
|
|
|
function spin_trylock(var t:r_spin_lock):Boolean;
|
|
procedure spin_lock(var t:r_spin_lock);
|
|
procedure spin_unlock(var t:r_spin_lock);
|
|
|
|
Procedure wait_until_equal(Var P:Pointer;V:Pointer);
|
|
Procedure wait_until_equal(Var P:SizeUint;V:SizeUint);
|
|
{$IF defined(CPUX86_64)}
|
|
Procedure wait_until_equal(Var P:DWORD;V:DWORD);
|
|
Procedure wait_until_equal(Var P:Integer;V:Integer);
|
|
{$ENDIF}
|
|
|
|
const
|
|
EVL_DIS=0; //disable
|
|
EVL_NEW=1; //new
|
|
EVL_ENB=2; //enable
|
|
|
|
function event_try_enable(Var P:Pointer):Boolean;
|
|
function event_try_enable(Var P:DWORD):Boolean;
|
|
function event_try_disable(Var P:Pointer):Boolean;
|
|
function event_try_disable(Var P:DWORD):Boolean;
|
|
procedure event_disable(Var P:Pointer);
|
|
procedure event_disable(Var P:DWORD);
|
|
|
|
implementation
|
|
|
|
Uses
|
|
atomic,
|
|
sys_kernel,
|
|
sys_signal;
|
|
|
|
Procedure backoff_exp.Wait;
|
|
Var
|
|
n:SizeUInt;
|
|
begin
|
|
if (m_nExpCur<=upper_bound) then
|
|
begin
|
|
For n:=0 to m_nExpCur-1 do
|
|
begin
|
|
SwYieldExecution;
|
|
end;
|
|
m_nExpCur:=m_nExpCur*2;
|
|
end else
|
|
begin
|
|
n:=-1000;
|
|
SwDelayExecution(False,@n);
|
|
end;
|
|
end;
|
|
|
|
Procedure backoff_exp.Reset;
|
|
begin
|
|
m_nExpCur:=lower_bound;
|
|
end;
|
|
|
|
function spin_trylock(Var P:Pointer):Boolean;
|
|
begin
|
|
Result:=XCHG(P,Pointer(1))=nil;
|
|
end;
|
|
|
|
function spin_trylock(Var P:SizeUint):Boolean;
|
|
begin
|
|
Result:=XCHG(P,1)=0;
|
|
end;
|
|
|
|
{$IF defined(CPUX86_64)}
|
|
function spin_trylock(Var P:DWORD):Boolean;
|
|
begin
|
|
Result:=XCHG(P,1)=0;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function spin_tryunlock(Var P:Pointer):Boolean;
|
|
begin
|
|
Result:=XCHG(P,nil)=Pointer(1);
|
|
end;
|
|
|
|
function spin_tryunlock(Var P:SizeUint):Boolean;
|
|
begin
|
|
Result:=XCHG(P,0)=1;
|
|
end;
|
|
|
|
{$IF defined(CPUX86_64)}
|
|
function spin_tryunlock(Var P:DWORD):Boolean;
|
|
begin
|
|
Result:=XCHG(P,0)=1;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure spin_lock(Var P:Pointer);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (XCHG(P,Pointer(1))<>nil) do bkoff.Wait;
|
|
end;
|
|
|
|
procedure spin_lock(Var P:SizeUint);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (XCHG(P,1)<>0) do bkoff.Wait;
|
|
end;
|
|
|
|
{$IF defined(CPUX86_64)}
|
|
procedure spin_lock(Var P:DWORD);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (XCHG(P,1)<>0) do bkoff.Wait;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure spin_unlock(Var P:Pointer);
|
|
begin
|
|
store_release(P,nil);
|
|
end;
|
|
|
|
procedure spin_unlock(Var P:SizeUint);
|
|
begin
|
|
store_release(P,0);
|
|
end;
|
|
|
|
{$IF defined(CPUX86_64)}
|
|
procedure spin_unlock(Var P:DWORD);
|
|
begin
|
|
store_release(P,0);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
//recrusive spin lock
|
|
|
|
function spin_trylock(var t:r_spin_lock):Boolean;
|
|
begin
|
|
Result:=True;
|
|
_sig_lock;
|
|
if spin_trylock(t._lock) then
|
|
begin
|
|
t.count:=0;
|
|
t.owner:=GetCurrentThreadId;
|
|
end else
|
|
if (t.owner=GetCurrentThreadId) then
|
|
begin
|
|
Inc(t.count);
|
|
end else
|
|
begin
|
|
Result:=False;
|
|
end;
|
|
_sig_unlock;
|
|
end;
|
|
|
|
procedure spin_lock(var t:r_spin_lock);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (not spin_trylock(t)) do bkoff.Wait;
|
|
end;
|
|
|
|
procedure spin_unlock(var t:r_spin_lock);
|
|
begin
|
|
_sig_lock;
|
|
if (t.count=0) then
|
|
begin
|
|
t.owner:=DWORD(-1);
|
|
spin_unlock(t._lock);
|
|
end else
|
|
begin
|
|
Dec(t.count);
|
|
end;
|
|
_sig_unlock;
|
|
end;
|
|
|
|
//
|
|
|
|
Procedure wait_until_equal(Var P:Pointer;V:Pointer);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (load_acq_rel(P)=V) do bkoff.Wait;
|
|
end;
|
|
|
|
Procedure wait_until_equal(Var P:SizeUint;V:SizeUint);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (load_acq_rel(P)=V) do bkoff.Wait;
|
|
end;
|
|
|
|
{$IF defined(CPUX86_64)}
|
|
Procedure wait_until_equal(Var P:DWORD;V:DWORD);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (load_acq_rel(P)=V) do bkoff.Wait;
|
|
end;
|
|
|
|
Procedure wait_until_equal(Var P:Integer;V:Integer);
|
|
Var
|
|
bkoff:backoff_exp;
|
|
begin
|
|
bkoff.Reset;
|
|
While (load_acq_rel(P)=V) do bkoff.Wait;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function event_try_enable(Var P:Pointer):Boolean;
|
|
begin
|
|
Result:=(XCHG(P,Pointer(EVL_NEW))=Pointer(EVL_DIS));
|
|
if Result then
|
|
begin
|
|
store_release(P,Pointer(EVL_ENB));
|
|
end;
|
|
end;
|
|
|
|
function event_try_enable(Var P:DWORD):Boolean;
|
|
begin
|
|
Result:=(XCHG(P,EVL_NEW)=EVL_DIS);
|
|
if Result then
|
|
begin
|
|
store_release(P,EVL_ENB);
|
|
end;
|
|
end;
|
|
|
|
function event_try_disable(Var P:Pointer):Boolean;
|
|
begin
|
|
Result:=False;
|
|
Case SizeUint(_CAS(P,Pointer(EVL_ENB),Pointer(EVL_DIS))) of
|
|
EVL_DIS,
|
|
EVL_ENB:Result:=True;
|
|
EVL_NEW:store_release(P,Pointer(EVL_ENB));
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function event_try_disable(Var P:DWORD):Boolean;
|
|
begin
|
|
Result:=False;
|
|
Case _CAS(P,EVL_ENB,EVL_DIS) of
|
|
EVL_DIS,
|
|
EVL_ENB:Result:=True;
|
|
EVL_NEW:store_release(P,EVL_ENB);
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
procedure event_disable(Var P:Pointer);
|
|
begin
|
|
store_release(P,Pointer(EVL_DIS));
|
|
end;
|
|
|
|
procedure event_disable(Var P:DWORD);
|
|
begin
|
|
store_release(P,EVL_DIS);
|
|
end;
|
|
|
|
end.
|
|
|