fpPS4/kernel/ps4_mutex.pas
2023-01-26 23:09:50 +03:00

581 lines
16 KiB
ObjectPascal

unit ps4_mutex;
{$mode objfpc}{$H+}
interface
uses
Windows,
sysutils,
sys_types;
type
p_pthread_mutex_attr=^pthread_mutex_attr_t;
pthread_mutex_attr_t=^pthread_mutex_attr;
pthread_mutex_attr=bitpacked record
_type:0..7; //3
_shared:0..1; //1
_protocol:0..3; //2
_align:0..67108863; //26
_prioceiling:Integer; //32
end;
p_pthread_mutex=^pthread_mutex;
pthread_mutex=^pthread_mutex_t;
pthread_mutex_t=packed record
valid:DWORD;
state:DWORD;
_type:DWORD;
rec_lock:DWORD;
owner:DWORD;
event:THandle;
name:array[0..31] of AnsiChar;
end;
ScePthreadMutex=pthread_mutex;
PScePthreadMutex=p_pthread_mutex;
const
SCE_PTHREAD_MUTEX_ERRORCHECK = 1; // Default POSIX mutex
SCE_PTHREAD_MUTEX_RECURSIVE = 2; // Recursive mutex
SCE_PTHREAD_MUTEX_NORMAL = 3; // No error checking
SCE_PTHREAD_MUTEX_ADAPTIVE = 4; // Adaptive mutex, spins briefly before blocking on lock
SCE_PTHREAD_MUTEX_DEFAULT = SCE_PTHREAD_MUTEX_ERRORCHECK;
PTHREAD_MUTEX_ERRORCHECK = SCE_PTHREAD_MUTEX_ERRORCHECK;
PTHREAD_MUTEX_RECURSIVE = SCE_PTHREAD_MUTEX_RECURSIVE;
PTHREAD_MUTEX_NORMAL = SCE_PTHREAD_MUTEX_NORMAL;
PTHREAD_MUTEX_ADAPTIVE = SCE_PTHREAD_MUTEX_ADAPTIVE;
PTHREAD_MUTEX_DEFAULT = SCE_PTHREAD_MUTEX_ERRORCHECK;{SCE_PTHREAD_MUTEX_RECURSIVE;}//PTHREAD_MUTEX_ERRORCHECK;
PTHREAD_PROCESS_PRIVATE=0;
PTHREAD_PROCESS_SHARED =1;
PTHREAD_PRIO_NONE =0;
PTHREAD_PRIO_INHERIT =1;
PTHREAD_PRIO_PROTECT =2;
PTHREAD_MUTEX_INITIALIZER =0;
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP=1;
function ps4_pthread_mutexattr_init(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_destroy(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_gettype(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_settype(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_getpshared(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_setpshared(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_getprotocol(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_setprotocol(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_getprioceiling(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutexattr_setprioceiling(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_lock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_timedlock(pMutex:p_pthread_mutex;ts:Ptimespec):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_trylock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_unlock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_init(pMutex:p_pthread_mutex;pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_destroy(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_mutex_setname_np(pMutex:p_pthread_mutex;name:Pchar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrInit(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrDestroy(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrGettype(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrSettype(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrGetprotocol(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrSetprotocol(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrGetprioceiling(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexattrSetprioceiling(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexInit(pMutex:PScePthreadMutex;pAttr:p_pthread_mutex_attr;str:PChar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexLock(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexTimedlock(pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexTrylock(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexUnlock(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadMutexDestroy(pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
//pthread_mutexattr_setkind_np
implementation
Uses
atomic,
sys_kernel,
sys_signal,
sys_time,
ps4_sema,
ps4_time;
function ps4_pthread_mutexattr_init(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
var
attr:pthread_mutex_attr_t;
begin
if (pAttr=nil) then Exit(EINVAL);
attr:=AllocMem(SizeOf(pthread_mutex_attr));
if (attr=nil) then Exit(ENOMEM);
attr^:=Default(pthread_mutex_attr);
attr^._type:=PTHREAD_MUTEX_DEFAULT;
pAttr^:=attr;
Result:=0;
end;
function ps4_pthread_mutexattr_destroy(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
var
attr:pthread_mutex_attr_t;
begin
if (pAttr=nil) then Exit(EINVAL);
attr:=pAttr^;
if (attr=nil) then Exit(EINVAL);
FreeMem(attr);
Result:=0;
end;
function ps4_pthread_mutexattr_gettype(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
t^:=pAttr^^._type;
Result:=0;
end;
function ps4_pthread_mutexattr_settype(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
Case t of
PTHREAD_MUTEX_ERRORCHECK:;
PTHREAD_MUTEX_RECURSIVE :;
PTHREAD_MUTEX_NORMAL :;
PTHREAD_MUTEX_ADAPTIVE :;
else
Exit(EINVAL);
end;
pAttr^^._type:=t;
Result:=0;
end;
function ps4_pthread_mutexattr_getpshared(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
t^:=pAttr^^._shared;
Result:=0;
end;
function ps4_pthread_mutexattr_setpshared(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
Case t of
PTHREAD_PROCESS_PRIVATE:;
PTHREAD_PROCESS_SHARED :;
else
Exit(EINVAL);
end;
pAttr^^._shared:=t;
Result:=0;
end;
function ps4_pthread_mutexattr_getprotocol(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
t^:=pAttr^^._protocol;
Result:=0;
end;
function ps4_pthread_mutexattr_setprotocol(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
Case t of
PTHREAD_PRIO_NONE :;
PTHREAD_PRIO_INHERIT:;
PTHREAD_PRIO_PROTECT:;
else
Exit(EINVAL);
end;
pAttr^^._protocol:=t;
Result:=0;
end;
function ps4_pthread_mutexattr_getprioceiling(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) or (t=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
t^:=pAttr^^._prioceiling;
Result:=0;
end;
function ps4_pthread_mutexattr_setprioceiling(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
if (pAttr=nil) then Exit(EINVAL);
if (pAttr^=nil) then Exit(EINVAL);
pAttr^^._prioceiling:=t;
Result:=0;
end;
///////////////////////////
Const
LIFE_MUTEX=$BAB1F00D;
DEAD_MUTEX=$DEADBEEF;
MS_Unlocked=0;
MS_Locked =1;
MS_Waiting =2;
const
PTHREAD_MUTEX_FREE=2;
function STATIC_INITIALIZER(m:pthread_mutex):Boolean; inline;
begin
Result:=False;
Case PtrUInt(m) of
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP:Result:=True;
end;
end;
function mutex_impl_init(m:p_pthread_mutex;mi:pthread_mutex;_type:Integer):pthread_mutex;
var
new_mi:pthread_mutex;
begin
new_mi:=SwAllocMem(SizeOf(pthread_mutex_t));
if (new_mi=nil) then Exit(new_mi);
new_mi^.valid:=LIFE_MUTEX;
new_mi^.state:=MS_Unlocked;
new_mi^._type:=_type;
new_mi^.owner:=DWORD(-1);
if CAS(m^,mi,new_mi) then
begin
Result:=new_mi;
end else
begin
SwFreeMem(new_mi);
Result:=m^;
end;
end;
function mutex_impl(m:p_pthread_mutex;var mi:pthread_mutex;default:Integer):Integer;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
Case PtrUInt(mi) of
PTHREAD_MUTEX_INITIALIZER :mi:=mutex_impl_init(m,mi,default);
PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP:mi:=mutex_impl_init(m,mi,PTHREAD_MUTEX_ADAPTIVE);
PTHREAD_MUTEX_FREE :Exit(EINVAL);
end;
if (mi=nil) then Exit(ENOMEM);
if not safe_test(mi^.valid,LIFE_MUTEX) then Exit(EINVAL);
Result:=0;
end;
function pthread_mutex_lock_intern(m:p_pthread_mutex;pTimeout:PQWORD;default:Integer):Integer;
var
mi:pthread_mutex;
old_state:DWORD;
ev:THandle;
begin
Result:=mutex_impl(m,mi,default);
if (Result<>0) then Exit;
old_state:=XCHG(mi^.state,MS_Locked);
if (old_state<>MS_Unlocked) then
begin
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
if (mi^.owner=GetCurrentThreadId) then
begin
CAS(mi^.state,MS_Locked,old_state);
if (mi^._type=PTHREAD_MUTEX_RECURSIVE) then
begin
Inc(mi^.rec_lock);
Exit(0);
end else
begin
Exit(EDEADLK);
end;
end;
if (mi^.event=0) then
begin
ev:=CreateEvent(nil,false,false,nil);
if (ev=0) then
Case GetLastError of
ERROR_ACCESS_DENIED:Exit(EPERM);
else
Exit(EPERM);
end;
if not CAS(mi^.event,0,ev) then
begin
CloseHandle(ev);
end;
end;
While (XCHG(mi^.state,MS_Waiting)<>MS_Unlocked) do
begin
Result:=do_sema_b_wait_intern(mi^.event,pTimeout);
if (Result<>0) then Exit;
end;
end;
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
begin
mi^.owner:=GetCurrentThreadId;
end;
Result:=0;
end;
function ps4_pthread_mutex_lock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
_sig_lock;
Result:=pthread_mutex_lock_intern(pMutex,nil,PTHREAD_MUTEX_DEFAULT);
_sig_unlock;
end;
function ps4_pthread_mutex_timedlock(pMutex:p_pthread_mutex;ts:Ptimespec):Integer; SysV_ABI_CDecl;
var
t:QWORD;
begin
if (ts=nil) then
begin
_sig_lock;
Result:=pthread_mutex_lock_intern(pMutex,nil,PTHREAD_MUTEX_DEFAULT);
_sig_unlock;
end else
begin
t:=_pthread_rel_time_in_ns(ts^);
_sig_lock;
Result:=pthread_mutex_lock_intern(pMutex,@t,PTHREAD_MUTEX_DEFAULT);
_sig_unlock;
end;
end;
function pthread_mutex_unlock(m:p_pthread_mutex;default:Integer):Integer;
var
mi:pthread_mutex;
begin
Result:=mutex_impl(m,mi,default);
if (Result<>0) then Exit;
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
begin
if (mi^.state=MS_Unlocked) then Exit(EPERM);
if (mi^.owner<>GetCurrentThreadId) then Exit(EPERM);
if (mi^.rec_lock>0) then
begin
Dec(mi^.rec_lock);
Exit(0);
end;
mi^.owner:=DWORD(-1);
end;
if XCHG(mi^.state,MS_Unlocked)=MS_Waiting then
begin
_sig_lock;
if not SetEvent(mi^.event) then Result:=EPERM;
_sig_unlock;
end;
end;
function ps4_pthread_mutex_unlock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_unlock(pMutex,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_trylock(m:p_pthread_mutex;default:Integer):Integer;
var
mi:pthread_mutex;
begin
Result:=mutex_impl(m,mi,default);
if (Result<>0) then Exit;
if CAS(mi^.state,MS_Unlocked,MS_Locked) then
begin
if (mi^._type<>PTHREAD_MUTEX_NORMAL) then
begin
mi^.owner:=GetCurrentThreadId;
end;
Exit(0);
end else
begin
if (mi^._type=PTHREAD_MUTEX_RECURSIVE) and (mi^.owner=GetCurrentThreadId) then
begin
Inc(mi^.rec_lock);
Exit(0);
end;
Exit(EBUSY);
end;
end;
function ps4_pthread_mutex_trylock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_trylock(pMutex,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_init(m:p_pthread_mutex;a:p_pthread_mutex_attr;str:PChar;default:Integer):Integer;
var
mi:pthread_mutex;
attr:pthread_mutex_attr_t;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
attr:=nil;
if (a<>nil) then
begin
attr:=a^;
end;
if (attr<>nil) then
begin
mi:=mutex_impl_init(m,mi,attr^._type);
end else
begin
mi:=mutex_impl_init(m,mi,default);
end;
if (mi=nil) then Exit(ENOMEM);
if not safe_test(mi^.valid,LIFE_MUTEX) then Exit(EINVAL);
if (str<>nil) then MoveChar0(str^,mi^.name,32);
Result:=0;
end;
function ps4_pthread_mutex_init(pMutex:p_pthread_mutex;pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_init(pMutex,pAttr,nil,PTHREAD_MUTEX_DEFAULT);
end;
function pthread_mutex_destroy(m:p_pthread_mutex):Integer;
var
mi:pthread_mutex;
begin
if (m=nil) then Exit(EINVAL);
mi:=m^;
if not STATIC_INITIALIZER(mi) then
begin
mi:=XCHG(m^,Pointer(PTHREAD_MUTEX_FREE));
if (mi=Pointer(PTHREAD_MUTEX_FREE)) then Exit(EINVAL);
if STATIC_INITIALIZER(mi) then Exit(0);
if not CAS(mi^.valid,LIFE_MUTEX,DEAD_MUTEX) then Exit(EINVAL);
_sig_lock;
if (mi^.event<>0) then CloseHandle(mi^.event);
FreeMem(mi);
_sig_unlock;
end;
Result:=0;
end;
function ps4_pthread_mutex_destroy(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=pthread_mutex_destroy(pMutex);
end;
function ps4_pthread_mutex_setname_np(pMutex:p_pthread_mutex;name:Pchar):Integer; SysV_ABI_CDecl;
var
m:pthread_mutex;
begin
if (pMutex=nil) then Exit(EINVAL);
m:=pMutex^;
if (m=nil) then Exit(EINVAL);
if (name<>nil) then
begin
FillChar(m^.name,32,0);
MoveChar0(name^,m^.name,32);
end;
Result:=0;
end;
//---------------------------------------------------------
//sce
function ps4_scePthreadMutexattrInit(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_init(pAttr));
end;
function ps4_scePthreadMutexattrDestroy(pAttr:p_pthread_mutex_attr):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_destroy(pAttr));
end;
function ps4_scePthreadMutexattrGettype(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_gettype(pAttr,t));
end;
function ps4_scePthreadMutexattrSettype(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_settype(pAttr,t));
end;
function ps4_scePthreadMutexattrGetprotocol(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_getprotocol(pAttr,t));
end;
function ps4_scePthreadMutexattrSetprotocol(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_setprotocol(pAttr,t));
end;
function ps4_scePthreadMutexattrGetprioceiling(pAttr:p_pthread_mutex_attr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_getprioceiling(pAttr,t));
end;
function ps4_scePthreadMutexattrSetprioceiling(pAttr:p_pthread_mutex_attr;t:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(ps4_pthread_mutexattr_setprioceiling(pAttr,t));
end;
//////////////
function ps4_scePthreadMutexLock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
_sig_lock;
Result:=px2sce(pthread_mutex_lock_intern(pMutex,nil,SCE_PTHREAD_MUTEX_DEFAULT));
_sig_unlock;
end;
function ps4_scePthreadMutexTimedlock(pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
var
t:QWORD;
begin
t:=_usec2nsec(usec);
_sig_lock;
Result:=px2sce(pthread_mutex_lock_intern(pMutex,@t,SCE_PTHREAD_MUTEX_DEFAULT));
_sig_unlock;
end;
function ps4_scePthreadMutexUnlock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_mutex_unlock(pMutex,SCE_PTHREAD_MUTEX_DEFAULT));
end;
function ps4_scePthreadMutexTrylock(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_mutex_trylock(pMutex,SCE_PTHREAD_MUTEX_DEFAULT));
end;
function ps4_scePthreadMutexInit(pMutex:PScePthreadMutex;pAttr:p_pthread_mutex_attr;str:PChar):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_mutex_init(pMutex,pAttr,str,SCE_PTHREAD_MUTEX_DEFAULT));
end;
function ps4_scePthreadMutexDestroy(pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
Result:=px2sce(pthread_mutex_destroy(pMutex));
end;
end.