mirror of https://github.com/red-prig/fpPS4.git
281 lines
5.1 KiB
Plaintext
281 lines
5.1 KiB
Plaintext
unit kern_mtx;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
sysutils,
|
|
ntapi;
|
|
|
|
type
|
|
t_fast_mutex=bitpacked record
|
|
recursion:WORD;
|
|
waiters :WORD;
|
|
owned :DWORD;
|
|
end;
|
|
|
|
p_mtx=^mtx;
|
|
mtx=packed record
|
|
n:PChar;
|
|
fast_mutex:t_fast_mutex;
|
|
{$IFDEF DEBUG_MTX}
|
|
debug_own:array[0..2] of Pointer;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
const
|
|
//Flags for lockinit().
|
|
LK_INIT_MASK =$0000FF;
|
|
LK_CANRECURSE=$000001;
|
|
LK_NODUP =$000002;
|
|
LK_NOPROFILE =$000004;
|
|
LK_NOSHARE =$000008;
|
|
LK_NOWITNESS =$000010;
|
|
LK_QUIET =$000020;
|
|
LK_ADAPTIVE =$000040;
|
|
|
|
//Additional attributes to be used in lockmgr().
|
|
LK_EATTR_MASK=$00FF00;
|
|
LK_INTERLOCK =$000100;
|
|
LK_NOWAIT =$000200;
|
|
LK_RETRY =$000400;
|
|
LK_SLEEPFAIL =$000800;
|
|
LK_TIMELOCK =$001000;
|
|
|
|
//Operations for lockmgr().
|
|
LK_TYPE_MASK =$FF0000;
|
|
LK_DOWNGRADE =$010000;
|
|
LK_DRAIN =$020000;
|
|
LK_EXCLOTHER =$040000;
|
|
LK_EXCLUSIVE =$080000;
|
|
LK_RELEASE =$100000;
|
|
LK_SHARED =$200000;
|
|
LK_UPGRADE =$400000;
|
|
LK_TRYUPGRADE=$800000;
|
|
|
|
LK_TOTAL_MASK=(LK_INIT_MASK or LK_EATTR_MASK or LK_TYPE_MASK);
|
|
|
|
procedure mtx_init (var m:mtx;name:PChar);
|
|
procedure mtx_destroy(var m:mtx);
|
|
procedure mtx_lock (var m:mtx);
|
|
function mtx_trylock(var m:mtx):Boolean;
|
|
procedure mtx_unlock (var m:mtx);
|
|
function mtx_owned (var m:mtx):Boolean;
|
|
procedure mtx_assert (var m:mtx);
|
|
|
|
implementation
|
|
|
|
{$IFDEF DEBUG_MTX}
|
|
uses
|
|
md_systm,
|
|
kern_thr;
|
|
{$ENDIF}
|
|
|
|
var
|
|
qhandle:THandle=0;
|
|
|
|
procedure mtx_init(var m:mtx;name:PChar); inline;
|
|
begin
|
|
m.n:=name;
|
|
QWORD(m.fast_mutex):=0;
|
|
end;
|
|
|
|
procedure mtx_destroy(var m:mtx); inline;
|
|
begin
|
|
//
|
|
end;
|
|
|
|
function GetKey(var m:mtx):Pointer; inline;
|
|
begin
|
|
Result:=Pointer(PTRUINT(@m) and (not PTRUINT(1)));
|
|
end;
|
|
|
|
procedure mtx_lock(var m:mtx);
|
|
var
|
|
i:Integer;
|
|
old:t_fast_mutex;
|
|
new:t_fast_mutex;
|
|
{$IFDEF DEBUG_MTX}
|
|
rbp:Pointer;
|
|
{$ENDIF}
|
|
begin
|
|
//Writeln('lock:',m.n,':',HexStr(@m));
|
|
{$IFDEF DEBUG_MTX}
|
|
if curkthread<>nil then
|
|
curkthread^.td_debug_mtx:=@m;
|
|
{$ENDIF}
|
|
|
|
i:=0;
|
|
|
|
repeat
|
|
QWORD(old):=System.InterlockedExchangeAdd64(QWORD(m.fast_mutex),0);
|
|
|
|
if (old.owned=0) or (old.owned=ThreadID) then
|
|
begin
|
|
new.recursion:=old.recursion+1;
|
|
new.waiters :=old.waiters;
|
|
new.owned :=ThreadID;
|
|
|
|
if System.InterlockedCompareExchange64(QWORD(m.fast_mutex),QWORD(new),QWORD(old)) = QWORD(old) then
|
|
begin
|
|
Break;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
Inc(i);
|
|
|
|
if (i>=100) then
|
|
begin
|
|
|
|
new:=old;
|
|
new.waiters:=new.waiters+1;
|
|
|
|
if System.InterlockedCompareExchange64(QWORD(m.fast_mutex),QWORD(new),QWORD(old)) = QWORD(old) then
|
|
begin
|
|
NtWaitForKeyedEvent(qhandle, GetKey(m), False, nil);
|
|
end;
|
|
|
|
i:=0;
|
|
end;
|
|
end;
|
|
|
|
until false;
|
|
|
|
{$IFDEF DEBUG_MTX}
|
|
if curkthread<>nil then
|
|
curkthread^.td_debug_mtx:=nil;
|
|
rbp:=nil;
|
|
asm
|
|
movq %rbp,rbp
|
|
end;
|
|
m.debug_own[0]:=md_fuword(PPointer(rbp)[1]); rbp:=md_fuword(PPointer(rbp)[0]);
|
|
m.debug_own[1]:=md_fuword(PPointer(rbp)[1]); rbp:=md_fuword(PPointer(rbp)[0]);
|
|
m.debug_own[2]:=md_fuword(PPointer(rbp)[1]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function mtx_trylock(var m:mtx):Boolean;
|
|
var
|
|
old:t_fast_mutex;
|
|
new:t_fast_mutex;
|
|
{$IFDEF DEBUG_MTX}
|
|
rbp:Pointer;
|
|
{$ENDIF}
|
|
begin
|
|
|
|
repeat
|
|
QWORD(old):=System.InterlockedExchangeAdd64(QWORD(m.fast_mutex),0);
|
|
|
|
if (old.owned=0) or (old.owned=ThreadID) then
|
|
begin
|
|
new.recursion:=old.recursion+1;
|
|
new.waiters :=old.waiters;
|
|
new.owned :=ThreadID;
|
|
|
|
if System.InterlockedCompareExchange64(QWORD(m.fast_mutex),QWORD(new),QWORD(old)) = QWORD(old) then
|
|
begin
|
|
Result:=True;
|
|
Break;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
Result:=False;
|
|
Break;
|
|
end;
|
|
|
|
until false;
|
|
|
|
{$IFDEF DEBUG_MTX}
|
|
if Result then
|
|
begin
|
|
rbp:=nil;
|
|
asm
|
|
movq %rbp,rbp
|
|
end;
|
|
m.debug_own[0]:=md_fuword(PPointer(rbp)[1]); rbp:=md_fuword(PPointer(rbp)[0]);
|
|
m.debug_own[1]:=md_fuword(PPointer(rbp)[1]); rbp:=md_fuword(PPointer(rbp)[0]);
|
|
m.debug_own[2]:=md_fuword(PPointer(rbp)[1]);
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure mtx_unlock(var m:mtx);
|
|
var
|
|
old:t_fast_mutex;
|
|
new:t_fast_mutex;
|
|
begin
|
|
mtx_assert(m);
|
|
|
|
repeat
|
|
|
|
QWORD(old):=System.InterlockedExchangeAdd64(QWORD(m.fast_mutex),0);
|
|
|
|
if (old.owned=0) or (old.owned<>ThreadID) or (old.recursion=0) then
|
|
begin
|
|
//current thread not owned
|
|
Exit;
|
|
end;
|
|
|
|
new:=old;
|
|
|
|
if (old.recursion=1) then
|
|
begin
|
|
new.recursion:=0;
|
|
new.owned :=0;
|
|
|
|
if (new.waiters<>0) then
|
|
begin
|
|
new.waiters:=new.waiters-1;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
new.recursion:=old.recursion-1;
|
|
end;
|
|
|
|
{$IFDEF DEBUG_MTX}
|
|
if (new.owned=0) then
|
|
begin
|
|
m.debug_own[0]:=nil;
|
|
m.debug_own[1]:=nil;
|
|
m.debug_own[2]:=nil;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
if System.InterlockedCompareExchange64(QWORD(m.fast_mutex),QWORD(new),QWORD(old)) = QWORD(old) then
|
|
begin
|
|
|
|
if (new.recursion=0) and (old.waiters<>0) then
|
|
begin
|
|
NtReleaseKeyedEvent(qhandle, GetKey(m), False, nil);
|
|
end;
|
|
|
|
Break;
|
|
end;
|
|
|
|
until false;
|
|
end;
|
|
|
|
function mtx_owned(var m:mtx):Boolean; inline;
|
|
begin
|
|
Result:=m.fast_mutex.owned=ThreadID;
|
|
end;
|
|
|
|
procedure mtx_assert(var m:mtx); inline;
|
|
begin
|
|
if not mtx_owned(m) then
|
|
begin
|
|
Assert(false,'mtx_assert:'+IntToStr(m.fast_mutex.owned)+'<>'+IntToStr(ThreadID));
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
NtCreateKeyedEvent(@qhandle, DWORD(-1), nil, 0);
|
|
|
|
end.
|
|
|