mirror of https://github.com/red-prig/fpPS4.git
761 lines
14 KiB
Plaintext
761 lines
14 KiB
Plaintext
unit kern_rwlock;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
{$DEFINE ALT_SRW1}
|
|
{/$DEFINE ALT_SRW2}
|
|
|
|
{$IF defined(ALT_SRW1) or defined(ALT_SRW2)}
|
|
procedure rw_rlock (Var SRWLock:Pointer);
|
|
procedure rw_runlock (Var SRWLock:Pointer);
|
|
procedure rw_wlock (Var SRWLock:Pointer);
|
|
procedure rw_wunlock (Var SRWLock:Pointer);
|
|
Function rw_try_rlock(Var SRWLock:Pointer):Boolean;
|
|
Function rw_try_wlock(Var SRWLock:Pointer):Boolean;
|
|
procedure rw_unlock (Var SRWLock:Pointer);
|
|
{$ELSE}
|
|
procedure rw_rlock (Var SRWLock:Pointer); stdcall; external 'kernel32' name 'AcquireSRWLockShared' ;
|
|
procedure rw_runlock (Var SRWLock:Pointer); stdcall; external 'kernel32' name 'ReleaseSRWLockShared' ;
|
|
procedure rw_wlock (Var SRWLock:Pointer); stdcall; external 'kernel32' name 'AcquireSRWLockExclusive' ;
|
|
procedure rw_wunlock (Var SRWLock:Pointer); stdcall; external 'kernel32' name 'ReleaseSRWLockExclusive' ;
|
|
Function rw_try_rlock(Var SRWLock:Pointer):Boolean; stdcall; external 'kernel32' name 'TryAcquireSRWLockShared' ;
|
|
Function rw_try_wlock(Var SRWLock:Pointer):Boolean; stdcall; external 'kernel32' name 'TryAcquireSRWLockExclusive';
|
|
{$ENDIF}
|
|
|
|
implementation
|
|
|
|
{$IF defined(ALT_SRW1) or defined(ALT_SRW2)}
|
|
uses
|
|
//mqueue,
|
|
ntapi,
|
|
windows;
|
|
{$ENDIF}
|
|
|
|
//https://github.com/wine-mirror/wine/blob/a581f11e3e536fbef1865f701c0db2444673d096/dlls/ntdll/sync.c
|
|
|
|
{
|
|
type
|
|
p_futex_entry=^futex_entry;
|
|
futex_entry=record
|
|
entry:STAILQ_ENTRY;
|
|
addr :Pointer;
|
|
tid :DWORD;
|
|
end;
|
|
|
|
p_futex_queue=^futex_queue;
|
|
futex_queue=record
|
|
queue:STAILQ_HEAD;
|
|
lock :Pointer;
|
|
end;
|
|
|
|
var
|
|
futex_queues:array[0..255] of futex_queue;
|
|
|
|
function get_futex_queue(addr:Pointer):p_futex_queue;
|
|
begin
|
|
Result:=@futex_queues[(QWORD(addr) shr 4) mod Length(futex_queues)];
|
|
end;
|
|
|
|
procedure spin_lock(var lock:Pointer);
|
|
begin
|
|
while (System.InterlockedCompareExchange(lock,Pointer(-1),nil)<>nil) do
|
|
begin
|
|
NtYieldExecution();
|
|
end;
|
|
end;
|
|
|
|
procedure spin_unlock(var lock:Pointer);
|
|
begin
|
|
System.InterlockedExchange(lock,nil);
|
|
end;
|
|
|
|
function compare_addr(addr,cmp:Pointer;size:Integer):Boolean; inline;
|
|
begin
|
|
case size of
|
|
1:Result:=(PBYTE(addr)^=PBYTE(cmp)^);
|
|
2:Result:=(PWORD(addr)^=PWORD(cmp)^);
|
|
4:Result:=(PDWORD(addr)^=PDWORD(cmp)^);
|
|
8:Result:=(PQWORD(addr)^=PQWORD(cmp)^);
|
|
else
|
|
Result:=False;
|
|
end;
|
|
end;
|
|
|
|
function RtlWaitOnAddress(addr,cmp:Pointer;size:Integer;timeout:PLARGE_INTEGER):DWORD;
|
|
var
|
|
queue:p_futex_queue;
|
|
entry:futex_entry;
|
|
begin
|
|
if (addr=nil) or
|
|
(not (size in [1,2,4,8])) then
|
|
begin
|
|
Exit(STATUS_INVALID_PARAMETER);
|
|
end;
|
|
|
|
queue:=get_futex_queue(addr);
|
|
|
|
entry.addr:=addr;
|
|
entry.tid :=ThreadId;
|
|
|
|
spin_lock(queue^.lock);
|
|
|
|
if not compare_addr(addr,cmp,size) then
|
|
begin
|
|
spin_unlock(queue^.lock);
|
|
Exit(0);
|
|
end;
|
|
|
|
if (queue^.queue.stqh_last=nil) then
|
|
begin
|
|
STAILQ_INIT(@queue^.queue);
|
|
end;
|
|
|
|
STAILQ_INSERT_TAIL(@queue^.queue,@entry,@entry.entry);
|
|
|
|
spin_unlock(queue^.lock);
|
|
|
|
Result:=NtWaitForAlertByThreadId(addr,timeout);
|
|
|
|
if (entry.addr<>nil) then
|
|
begin
|
|
spin_lock(queue^.lock);
|
|
//
|
|
if (entry.addr<>nil) then
|
|
begin
|
|
STAILQ_REMOVE(@queue^.queue,@entry,@entry.entry);
|
|
end;
|
|
//
|
|
spin_unlock(queue^.lock);
|
|
end;
|
|
|
|
if (Result=STATUS_ALERTED) then
|
|
begin
|
|
Result:=STATUS_SUCCESS;
|
|
end;
|
|
end;
|
|
|
|
procedure RtlWakeAddressAll(addr:Pointer);
|
|
var
|
|
queue:p_futex_queue;
|
|
entry,next:p_futex_entry;
|
|
tids:array[0..63] of DWORD;
|
|
i,count:Integer;
|
|
begin
|
|
if (addr=nil) then Exit;
|
|
|
|
queue:=get_futex_queue(addr);
|
|
|
|
count:=0;
|
|
|
|
spin_lock(queue^.lock);
|
|
|
|
if (queue^.queue.stqh_last=nil) then
|
|
begin
|
|
STAILQ_INIT(@queue^.queue);
|
|
end;
|
|
|
|
entry:=STAILQ_FIRST(@queue^.queue);
|
|
while (entry<>nil) do
|
|
begin
|
|
next:=STAILQ_NEXT(entry,@entry^.entry);
|
|
//
|
|
if (entry^.addr=addr) then
|
|
begin
|
|
entry^.addr:=nil;
|
|
|
|
STAILQ_REMOVE(@queue^.queue,entry,@entry^.entry);
|
|
|
|
if (count<Length(tids)) then
|
|
begin
|
|
tids[count]:=entry^.tid;
|
|
Inc(count);
|
|
end else
|
|
begin
|
|
NtAlertThreadByThreadId(entry^.tid);
|
|
end;
|
|
end;
|
|
//
|
|
entry:=next;
|
|
end;
|
|
|
|
spin_unlock(queue^.lock);
|
|
|
|
if (count<>0) then
|
|
For i:=0 to count-1 do
|
|
begin
|
|
NtAlertThreadByThreadId(tids[i]);
|
|
end;
|
|
end;
|
|
|
|
procedure RtlWakeAddressSingle(addr:Pointer);
|
|
var
|
|
queue:p_futex_queue;
|
|
entry:p_futex_entry;
|
|
tid:DWORD;
|
|
begin
|
|
if (addr=nil) then Exit;
|
|
|
|
queue:=get_futex_queue(addr);
|
|
|
|
tid:=0;
|
|
|
|
spin_lock(queue^.lock);
|
|
|
|
if (queue^.queue.stqh_last=nil) then
|
|
begin
|
|
STAILQ_INIT(@queue^.queue);
|
|
end;
|
|
|
|
entry:=STAILQ_FIRST(@queue^.queue);
|
|
while (entry<>nil) do
|
|
begin
|
|
if (entry^.addr=addr) then
|
|
begin
|
|
tid:=entry^.tid;
|
|
|
|
entry^.addr:=nil;
|
|
|
|
STAILQ_REMOVE(@queue^.queue,entry,@entry^.entry);
|
|
Break;
|
|
end;
|
|
//
|
|
entry:=STAILQ_NEXT(entry,@entry^.entry);
|
|
end;
|
|
|
|
spin_unlock(queue^.lock);
|
|
|
|
if (tid<>0) then
|
|
begin
|
|
NtAlertThreadByThreadId(tid);
|
|
end;
|
|
end;
|
|
}
|
|
|
|
{$IF defined(ALT_SRW1) or defined(ALT_SRW2)}
|
|
|
|
function RtlWaitOnAddress (addr,cmp:Pointer;size:QWORD;timeout:PLARGE_INTEGER):DWORD; stdcall; external 'ntdll';
|
|
procedure RtlWakeAddressAll (addr:Pointer); stdcall; external 'ntdll';
|
|
procedure RtlWakeAddressSingle(addr:Pointer); stdcall; external 'ntdll';
|
|
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ALT_SRW1}
|
|
|
|
type
|
|
p_srw_lock=^srw_lock;
|
|
srw_lock=packed record
|
|
exclusive_waiters:Smallint;
|
|
owners :Word;
|
|
end;
|
|
|
|
t_union_1=packed record
|
|
case Byte of
|
|
0:(r:Pointer);
|
|
1:(s:p_srw_lock);
|
|
2:(l:PDWORD);
|
|
end;
|
|
|
|
t_union_2=packed record
|
|
case Byte of
|
|
0:(s:srw_lock);
|
|
1:(l:DWORD);
|
|
end;
|
|
|
|
procedure InterlockedExchangeAdd16(addr:Pointer;New:WORD); assembler; nostackframe; sysv_abi_default;
|
|
asm
|
|
lock xadd %si,(%rdi)
|
|
end;
|
|
|
|
procedure rw_wlock(Var SRWLock:Pointer);
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
wait:Boolean;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
InterlockedExchangeAdd16(@u.s^.exclusive_waiters,2);
|
|
|
|
repeat
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if (old.s.owners=0) then
|
|
begin
|
|
new.s.owners:=1;
|
|
Dec(new.s.exclusive_waiters,2);
|
|
new.s.exclusive_waiters:=new.s.exclusive_waiters or 1;
|
|
wait:=FALSE;
|
|
end else
|
|
begin
|
|
wait:=TRUE;
|
|
end;
|
|
until (System.InterlockedCompareExchange(u.l^,new.l,old.l) = old.l);
|
|
|
|
if (not wait) then Exit;
|
|
RtlWaitOnAddress(@u.s^.owners,@new.s.owners,sizeof(Smallint),nil);
|
|
until false;
|
|
end;
|
|
|
|
procedure rw_rlock(Var SRWLock:Pointer);
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
wait:Boolean;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
repeat
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if (old.s.exclusive_waiters=0) then
|
|
begin
|
|
Inc(new.s.owners);
|
|
wait:=FALSE;
|
|
end else
|
|
begin
|
|
wait:=TRUE;
|
|
end;
|
|
until (System.InterlockedCompareExchange(u.l^,new.l,old.l) = old.l);
|
|
|
|
if (not wait) then Exit;
|
|
RtlWaitOnAddress(u.s,@new.s,sizeof(srw_lock),nil);
|
|
until false;
|
|
end;
|
|
|
|
function rw_try_wlock(Var SRWLock:Pointer):Boolean;
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if (old.s.owners=0) then
|
|
begin
|
|
new.s.owners:=1;
|
|
new.s.exclusive_waiters:=new.s.exclusive_waiters or 1;
|
|
Result:=TRUE;
|
|
end else
|
|
begin
|
|
Exit(FALSE);
|
|
end;
|
|
until (System.InterlockedCompareExchange(u.l^,new.l,old.l) = old.l);
|
|
end;
|
|
|
|
function rw_try_rlock(Var SRWLock:Pointer):Boolean;
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if (old.s.exclusive_waiters=0) then
|
|
begin
|
|
Inc(new.s.owners);
|
|
Result:=TRUE;
|
|
end else
|
|
begin
|
|
Exit(FALSE);
|
|
end;
|
|
until (System.InterlockedCompareExchange(u.l^,new.l,old.l) = old.l);
|
|
end;
|
|
|
|
procedure rw_wunlock(Var SRWLock:Pointer);
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if ((old.s.exclusive_waiters and 1)=0) then
|
|
begin
|
|
Assert(false,'Lock 0x'+HexStr(@SRWLock)+' is not owned exclusive!');
|
|
end;
|
|
|
|
new.s.owners:=0;
|
|
new.s.exclusive_waiters:=new.s.exclusive_waiters and (not 1);
|
|
until (System.InterlockedCompareExchange(u.l^,new.l,old.l) = old.l);
|
|
|
|
if (new.s.exclusive_waiters<>0) then
|
|
begin
|
|
RtlWakeAddressSingle(@u.s^.owners);
|
|
end else
|
|
begin
|
|
RtlWakeAddressAll(u.s);
|
|
end;
|
|
end;
|
|
|
|
procedure rw_runlock(Var SRWLock:Pointer);
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if ((old.s.exclusive_waiters and 1)<>0) then
|
|
begin
|
|
Assert(false,'Lock 0x'+HexStr(@SRWLock)+' is owned exclusive!');
|
|
end else
|
|
if (old.s.owners=0) then
|
|
begin
|
|
Assert(false,'Lock 0x'+HexStr(@SRWLock)+' is not owned shared!');
|
|
end;
|
|
|
|
Dec(new.s.owners);
|
|
until (System.InterlockedCompareExchange(u.l^,new.l,old.l) = old.l);
|
|
|
|
if (new.s.owners=0) then
|
|
begin
|
|
RtlWakeAddressSingle(@u.s^.owners);
|
|
end;
|
|
end;
|
|
|
|
procedure rw_unlock(Var SRWLock:Pointer);
|
|
var
|
|
u:t_union_1;
|
|
old,new:t_union_2;
|
|
shared:Boolean;
|
|
begin
|
|
u.r:=@SRWLock;
|
|
|
|
repeat
|
|
old.s:=u.s^;
|
|
new:=old;
|
|
|
|
if ((old.s.exclusive_waiters and 1)<>0) then
|
|
begin
|
|
shared:=False;
|
|
end else
|
|
if (old.s.owners=0) then
|
|
begin
|
|
Exit;
|
|
end else
|
|
begin
|
|
shared:=True;
|
|
end;
|
|
|
|
if shared then
|
|
begin
|
|
Dec(new.s.owners);
|
|
end else
|
|
begin
|
|
new.s.owners:=0;
|
|
new.s.exclusive_waiters:=new.s.exclusive_waiters and (not 1);
|
|
end;
|
|
|
|
until not (System.InterlockedCompareExchange(u.l^,new.l,old.l)<>old.l);
|
|
|
|
if shared then
|
|
begin
|
|
if (new.s.owners=0) then
|
|
begin
|
|
RtlWakeAddressSingle(@u.s^.owners);
|
|
end;
|
|
end else
|
|
begin
|
|
if (new.s.exclusive_waiters<>0) then
|
|
begin
|
|
RtlWakeAddressSingle(@u.s^.owners);
|
|
end else
|
|
begin
|
|
RtlWakeAddressAll(u.s);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ALT_SRW2}
|
|
|
|
Const
|
|
MAX_SPIN=10;
|
|
|
|
SRW_MASK_READERS=QWORD($000000007FFFFFFF);
|
|
SRW_FLAG_WRITING=QWORD($0000000080000000);
|
|
SRW_MASK_WAITERS=QWORD($7FFFFFFF00000000);
|
|
SRW_FLAG_READIED=QWORD($8000000000000000);
|
|
|
|
SRW_INC_WAITER =QWORD($0000000100000000);
|
|
|
|
function ReaderCount(lock:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=DWORD(lock and SRW_MASK_READERS);
|
|
end;
|
|
|
|
function SetReaders(lock:QWORD;readers:DWORD):QWORD; inline;
|
|
begin
|
|
Result:=(lock and (not SRW_MASK_READERS)) or readers;
|
|
end;
|
|
|
|
function WaitingCount(lock:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=DWORD((lock and SRW_MASK_WAITERS) shr 32);
|
|
end;
|
|
|
|
function SetWaiting(lock:QWORD;waiting:DWORD):QWORD; inline;
|
|
begin
|
|
Result:=(lock and (not SRW_MASK_WAITERS)) or (QWORD(waiting) shl 32);
|
|
end;
|
|
|
|
function IncWaiting(var lock:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=System.InterlockedExchangeAdd64(lock,SRW_INC_WAITER)+SRW_INC_WAITER;
|
|
end;
|
|
|
|
function DecWaiting(var lock:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=System.InterlockedExchangeAdd64(lock,QWORD(-SRW_INC_WAITER))+QWORD(-SRW_INC_WAITER);
|
|
end;
|
|
|
|
function Writer(lock:QWORD):Boolean; inline;
|
|
begin
|
|
Result:=(lock and SRW_FLAG_WRITING)<>0;
|
|
end;
|
|
|
|
function SetWriter(lock:QWORD;writer:Boolean):QWORD; inline;
|
|
begin
|
|
if writer then
|
|
Result:=lock or SRW_FLAG_WRITING
|
|
else
|
|
Result:=lock and (not SRW_FLAG_WRITING);
|
|
end;
|
|
|
|
function AllClear(lock:QWORD):Boolean; inline;
|
|
begin
|
|
Result:=(lock and (SRW_MASK_READERS or SRW_FLAG_WRITING))=0;
|
|
end;
|
|
|
|
function Initialized(lock:QWORD):Boolean; inline;
|
|
begin
|
|
Result:=(lock and SRW_FLAG_READIED)<>0;
|
|
end;
|
|
|
|
function SetInitialized(lock:QWORD;init:Boolean):QWORD; inline;
|
|
begin
|
|
if init then
|
|
Result:=lock or SRW_FLAG_READIED
|
|
else
|
|
Result:=lock and (not SRW_FLAG_READIED);
|
|
end;
|
|
|
|
Procedure rw_rlock(Var SRWLock:Pointer);
|
|
label
|
|
_next;
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
i:SizeUInt;
|
|
temp,new:QWORD;
|
|
begin
|
|
i:=0;
|
|
repeat
|
|
temp:=vLock;
|
|
|
|
if not Writer(temp) then
|
|
begin
|
|
|
|
if System.InterlockedCompareExchange64(vLock,SetReaders(temp,ReaderCount(temp) + 1),temp) = temp then
|
|
begin
|
|
Exit;
|
|
end else
|
|
begin
|
|
goto _next;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
|
|
if (i<MAX_SPIN) then
|
|
begin
|
|
NtYieldExecution;
|
|
goto _next;
|
|
end;
|
|
|
|
new:=IncWaiting(vLock);
|
|
|
|
i:=0;
|
|
RtlWaitOnAddress(@SRWLock,@new,sizeof(QWORD),nil);
|
|
|
|
DecWaiting(vLock);
|
|
end;
|
|
|
|
_next:
|
|
Inc(i);
|
|
until False;
|
|
end;
|
|
|
|
Procedure rw_wlock(Var SRWLock:Pointer);
|
|
label
|
|
_next;
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
i:SizeUInt;
|
|
temp,new:QWORD;
|
|
begin
|
|
i:=0;
|
|
repeat
|
|
temp:=vLock;
|
|
|
|
if AllClear(temp) then
|
|
begin
|
|
|
|
if System.InterlockedCompareExchange64(vLock,SetWriter(temp,true),temp) = temp then
|
|
begin
|
|
Exit;
|
|
end else
|
|
begin
|
|
goto _next;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
|
|
if (i<MAX_SPIN) then
|
|
begin
|
|
NtYieldExecution;
|
|
goto _next;
|
|
end;
|
|
|
|
new:=IncWaiting(vLock);
|
|
|
|
i:=0;
|
|
RtlWaitOnAddress(@SRWLock,@new,sizeof(QWORD),nil);
|
|
|
|
DecWaiting(vLock);
|
|
end;
|
|
|
|
_next:
|
|
Inc(i);
|
|
until False;
|
|
end;
|
|
|
|
procedure rw_wunlock(Var SRWLock:Pointer);
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
temp:QWORD;
|
|
begin
|
|
repeat
|
|
temp:=vLock;
|
|
|
|
Assert(Writer(temp));
|
|
|
|
until System.InterlockedCompareExchange64(vLock,SetWriter(temp,false),temp) = temp;
|
|
|
|
RtlWakeAddressAll(@SRWLock);
|
|
end;
|
|
|
|
procedure rw_runlock(Var SRWLock:Pointer);
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
temp:QWORD;
|
|
begin
|
|
repeat
|
|
temp:=vLock;
|
|
|
|
Assert(ReaderCount(temp) > 0);
|
|
|
|
until System.InterlockedCompareExchange64(vLock,SetReaders(temp,ReaderCount(temp) - 1),temp) = temp;
|
|
|
|
if (ReaderCount(temp)=1) and (WaitingCount(temp)<>0) then
|
|
begin
|
|
RtlWakeAddressSingle(@SRWLock);
|
|
end;
|
|
end;
|
|
|
|
Procedure rw_unlock(Var SRWLock:Pointer);
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
temp:QWORD;
|
|
begin
|
|
repeat
|
|
|
|
temp:=vLock;
|
|
if ReaderCount(temp)=0 then
|
|
begin
|
|
//rw_wunlock
|
|
|
|
if System.InterlockedCompareExchange64(vLock,SetWriter(temp,false),temp) = temp then
|
|
begin
|
|
RtlWakeAddressAll(@SRWLock);
|
|
Break;
|
|
end;
|
|
//
|
|
end else
|
|
begin
|
|
//rw_runlock
|
|
|
|
if System.InterlockedCompareExchange64(vLock,SetReaders(temp,ReaderCount(temp) - 1),temp) = temp then
|
|
begin
|
|
|
|
if (ReaderCount(temp)=1) and (WaitingCount(temp)<>0) then
|
|
begin
|
|
RtlWakeAddressSingle(@SRWLock);
|
|
end;
|
|
|
|
Break;
|
|
end;
|
|
//
|
|
end;
|
|
|
|
until false;
|
|
end;
|
|
|
|
function rw_try_rlock(Var SRWLock:Pointer):Boolean;
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
temp:QWORD;
|
|
begin
|
|
Result:=False;
|
|
temp:=vLock;
|
|
if not Writer(temp) then
|
|
begin
|
|
if System.InterlockedCompareExchange64(vLock,SetReaders(temp,ReaderCount(temp) + 1),temp) = temp then
|
|
begin
|
|
Result:=True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function rw_try_wlock(Var SRWLock:Pointer):Boolean;
|
|
Var
|
|
vLock:QWORD absolute SRWLock;
|
|
temp:QWORD;
|
|
begin
|
|
Result:=False;
|
|
temp:=vLock;
|
|
if AllClear(temp) then
|
|
begin
|
|
if System.InterlockedCompareExchange64(vLock,SetWriter(temp,true),temp) = temp then
|
|
begin
|
|
Result:=True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
end.
|
|
|