unit ps4_cond;

{$mode objfpc}{$H+}

interface

uses
 Windows,
 ntapi,
 sys_types,
 ps4_mutex;

type
 p_pthread_condattr=^pthread_condattr_t;
 pthread_condattr_t=^pthread_condattr;
 pthread_condattr=bitpacked record
  _shared:0..1;         //1
  _clock:0..31;         //5
  _align:0..67108863;   //26
  _align2:Integer;      //32
 end;

 p_pthread_cond=^pthread_cond;
 pthread_cond=^pthread_cond_t;
 pthread_cond_t=packed record
  valid:DWORD;
  busy :DWORD;
  waiters_count_:DWORD;
  waiters_count_unblock_:DWORD;
  waiters_count_gone_:DWORD;
  value_q:Integer;
  value_b:Integer;
  waiters_count_lock_:TRTLCriticalSection;
  waiters_q_lock_:TRTLCriticalSection;
  waiters_b_lock_:TRTLCriticalSection;
  sema_q:THandle;
  sema_b:THandle;
  name:array[0..31] of AnsiChar;
 end;

 PScePthreadCond=p_pthread_cond;

Const
 PTHREAD_COND_INITIALIZER=nil;

function ps4_pthread_condattr_init(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_destroy(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_getclock(pAttr:p_pthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_setclock(pAttr:p_pthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_getpshared(pAttr:p_pthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
function ps4_pthread_condattr_setpshared(pAttr:p_pthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;

function ps4_pthread_cond_init(pCond:p_pthread_cond;pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_destroy(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;

function ps4_pthread_cond_signal(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_broadcast(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;

function ps4_pthread_cond_wait(pCond:p_pthread_cond;pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
function ps4_pthread_cond_timedwait(pCond:p_pthread_cond;pMutex:p_pthread_mutex;ptime:Ptimespec):Integer; SysV_ABI_CDecl;

function ps4_scePthreadCondattrInit(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondattrDestroy(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;

function ps4_scePthreadCondInit(pCond:PScePthreadCond;pAttr:p_pthread_condattr;name:Pchar):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondDestroy(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;

function ps4_scePthreadCondSignal(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondWait(pCond:PScePthreadCond;pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondTimedwait(pCond:PScePthreadCond;pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
function ps4_scePthreadCondBroadcast(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;

implementation

Uses
 spinlock,
 sys_kernel,
 sys_signal,
 sys_time,
 ps4_sema,
 ps4_time;

function ps4_pthread_condattr_init(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
var
 attr:pthread_condattr_t;
begin
 if (pAttr=nil) then Exit(EINVAL);
 attr:=AllocMem(SizeOf(pthread_condattr));
 if (attr=nil) then Exit(ENOMEM);
 pAttr^:=attr;
 Result:=0;
end;

function ps4_pthread_condattr_destroy(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
var
 attr:pthread_condattr_t;
begin
 if (pAttr=nil) then Exit(EINVAL);
 attr:=pAttr^;
 if (attr=nil) then Exit(EINVAL);
 FreeMem(attr);
 Result:=0;
end;

function ps4_pthread_condattr_getclock(pAttr:p_pthread_condattr;t:PInteger):Integer; SysV_ABI_CDecl;
begin
 if (pAttr=nil) or (t=nil) then Exit(EINVAL);
 if (pAttr^=nil) then Exit(EINVAL);
 t^:=pAttr^^._clock;
 Result:=0;
end;

function ps4_pthread_condattr_setclock(pAttr:p_pthread_condattr;t:Integer):Integer; SysV_ABI_CDecl;
begin
 if (pAttr=nil) then Exit(EINVAL);
 if (pAttr^=nil) then Exit(EINVAL);
 Case t of
  CLOCK_REALTIME         :;
  CLOCK_VIRTUAL          :;
  CLOCK_PROF             :;
  CLOCK_MONOTONIC        :;
  CLOCK_UPTIME           :;
  CLOCK_UPTIME_PRECISE   :;
  CLOCK_UPTIME_FAST      :;
  CLOCK_REALTIME_PRECISE :;
  CLOCK_REALTIME_FAST    :;
  CLOCK_MONOTONIC_PRECISE:;
  CLOCK_MONOTONIC_FAST   :;
  CLOCK_SECOND           :;
  CLOCK_THREAD_CPUTIME_ID:;
  CLOCK_PROCTIME         :;
  CLOCK_EXT_NETWORK      :;
  CLOCK_EXT_DEBUG_NETWORK:;
  CLOCK_EXT_AD_NETWORK   :;
  CLOCK_EXT_RAW_NETWORK  :;
  else
   Exit(EINVAL);
 end;
 pAttr^^._clock:=t;
 Result:=0;
end;

function ps4_pthread_condattr_getpshared(pAttr:p_pthread_condattr;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_condattr_setpshared(pAttr:p_pthread_condattr;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;

Const
 LIFE_COND=$C0BAB1FD;
 DEAD_COND=$C0DEADBF;

type
 psCondWaitHelper=^sCondWaitHelper;
 sCondWaitHelper=packed record
  c:pthread_cond;
  external_mutex:p_pthread_mutex;
  r:Pinteger;
 end;

var
 cond_locked:Pointer=nil;

function STATIC_COND_INITIALIZER(x:p_pthread_cond):Boolean; inline;
begin
 Result:=(x^=PTHREAD_COND_INITIALIZER);
end;

function pthread_cond_init(c:p_pthread_cond;a:p_pthread_condattr;str:PChar):Integer;
var
 _c:pthread_cond;
begin
 if (c=nil) then Exit(EINVAL);

 _c:=AllocMem(SizeOf(pthread_cond_t));
 if (_c=nil) then Exit(ENOMEM);

 _c^.valid:=DEAD_COND;
 _c^.sema_q:=CreateSemaphore(nil,0,$7fffffff,nil);

 if (_c^.sema_q=0) then
 begin
  FreeMem(_c);
  c^:=nil;
  Exit(EAGAIN);
 end;
 _c^.sema_b:=CreateSemaphore(nil,0,$7fffffff,nil);

 if (_c^.sema_b=0) then
 begin
  CloseHandle(_c^.sema_q);
  FreeMem(_c);
  c^:=nil;
  Exit(EAGAIN);
 end;

 System.InitCriticalSection(_c^.waiters_count_lock_);
 System.InitCriticalSection(_c^.waiters_b_lock_);
 System.InitCriticalSection(_c^.waiters_q_lock_);

 _c^.value_q:=0;
 _c^.value_b:=1;
 _c^.valid:=LIFE_COND;

 if (str<>nil) then MoveChar0(str^,_c^.name,32);

 c^:=_c;
 Result:=0;
end;

function cond_static_init(c:p_pthread_cond):Integer;
var
 r:Integer;
begin
 r:=0;
 spin_lock(cond_locked);
 if (c=nil) then Exit(EINVAL);

 if STATIC_COND_INITIALIZER(c) then
 begin
  _sig_lock;
  r:=pthread_cond_init(c,nil,nil);
  _sig_unlock;
 end;

 spin_unlock(cond_locked);
 Result:=r;
end;

function pthread_cond_destroy(pCond:p_pthread_cond):Integer;
var
 r:Integer;
 _c:pthread_cond;
begin
 if (pCond=nil) then Exit(EINVAL);

 if STATIC_COND_INITIALIZER(pCond) then
 begin
  spin_lock(cond_locked);
  if STATIC_COND_INITIALIZER(pCond) then
  begin
   r:=0;
  end else
  begin
   r:=EBUSY;
  end;
  spin_unlock(cond_locked);
  Exit(r);
 end;

 _c:=pCond^;
 r:=do_sema_b_wait(_c^.sema_b,nil,_c^.waiters_b_lock_,_c^.value_b);
 if (r<>0) then Exit(r);

 if (System.TryEnterCriticalSection(_c^.waiters_count_lock_)=0) then
 begin
  do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
  Exit(EBUSY);
 end;

 if (_c^.waiters_count_ > _c^.waiters_count_gone_) then
 begin
  r:=do_sema_b_release(_c^.sema_b, 1,_c^.waiters_b_lock_,_c^.value_b);
  if (r=0) then r:=EBUSY;
  System.LeaveCriticalSection(_c^.waiters_count_lock_);
  Exit(r);
 end;

 pCond^:=nil;

 do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);

 if (not CloseHandle(_c^.sema_q)) and (r=0) then r:=EINVAL;
 if (not CloseHandle(_c^.sema_b)) and (r=0) then r:=EINVAL;

 System.LeaveCriticalSection (_c^.waiters_count_lock_);
 System.DoneCriticalSection(_c^.waiters_count_lock_);
 System.DoneCriticalSection(_c^.waiters_b_lock_);
 System.DoneCriticalSection(_c^.waiters_q_lock_);
 _c^.valid:=DEAD_COND;
 FreeMem(_c);

 Result:=0;
end;

function pthread_cond_signal(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;
var
 r:Integer;
 _c:pthread_cond;
begin
 if (pCond=nil) then Exit(EINVAL);

 _c:=pCond^;
 if (_c=PTHREAD_COND_INITIALIZER) then
  Exit(0)
 else
 if not safe_test(_c^.valid,LIFE_COND) then
  Exit(EINVAL);

 //Writeln('pthread_cond_signal:',_c^.name);

 SwEnterCriticalSection(_c^.waiters_count_lock_);

 if (_c^.waiters_count_unblock_<>0) then
 begin
  if (_c^.waiters_count_=0) then
  begin
   System.LeaveCriticalSection(_c^.waiters_count_lock_);
   Exit(0);
  end;

  Dec(_c^.waiters_count_);
  Inc(_c^.waiters_count_unblock_);
 end else
 if (_c^.waiters_count_>_c^.waiters_count_gone_) then
 begin

  r:=do_sema_b_wait(_c^.sema_b,nil,_c^.waiters_b_lock_,_c^.value_b);

  if (r<>0) then
  begin
   System.LeaveCriticalSection (_c^.waiters_count_lock_);
   Exit(r);
  end;

  if (_c^.waiters_count_gone_<>0) then
  begin
   Dec(_c^.waiters_count_,_c^.waiters_count_gone_);
   _c^.waiters_count_gone_:=0;
  end;

  Dec(_c^.waiters_count_);
  _c^.waiters_count_unblock_:=1;

 end else
 begin
  System.LeaveCriticalSection(_c^.waiters_count_lock_);
  Exit(0);
 end;

 System.LeaveCriticalSection(_c^.waiters_count_lock_);

 Result:=do_sema_b_release(_c^.sema_q,1,_c^.waiters_q_lock_,_c^.value_q);
end;

function pthread_cond_broadcast(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;
var
 r,relCnt:Integer;
 _c:pthread_cond;
begin
 if (pCond=nil) then Exit(EINVAL);
 relCnt:=0;

 _c:=pCond^;
 if (_c=PTHREAD_COND_INITIALIZER) then
  Exit(0)
 else
 if not safe_test(_c^.valid,LIFE_COND) then
  Exit(EINVAL);

 //Writeln('>pthread_cond_broadcast:',HexStr(_c),':',_c^.name);

 SwEnterCriticalSection(_c^.waiters_count_lock_);

 if (_c^.waiters_count_unblock_<>0) then
 begin
  if (_c^.waiters_count_=0) then
  begin
   System.LeaveCriticalSection (_c^.waiters_count_lock_);
   //Writeln('<1_pthread_cond_broadcast:',HexStr(_c),':',_c^.name);
   Exit(0);
  end;
  relCnt:=_c^.waiters_count_;
  _c^.waiters_count_:=0;
  Inc(_c^.waiters_count_unblock_,relCnt);
 end else
 if (_c^.waiters_count_>_c^.waiters_count_gone_) then
 begin

  r:=do_sema_b_wait(_c^.sema_b,nil,_c^.waiters_b_lock_,_c^.value_b);

  if (r<>0) then
  begin
   System.LeaveCriticalSection(_c^.waiters_count_lock_);
   //Writeln('<2_pthread_cond_broadcast:',HexStr(_c),':',_c^.name);
   Exit(r);
  end;

  if (_c^.waiters_count_gone_<>0) then
  begin
   Dec(_c^.waiters_count_,_c^.waiters_count_gone_);
   _c^.waiters_count_gone_:=0;
  end;

  relCnt:=_c^.waiters_count_;
  _c^.waiters_count_:=0;
  _c^.waiters_count_unblock_:=relCnt;

 end else
 begin
  System.LeaveCriticalSection(_c^.waiters_count_lock_);
  //Writeln('<3_pthread_cond_broadcast:',HexStr(_c),':',_c^.name);
  Exit(0);
 end;

 LeaveCriticalSection(_c^.waiters_count_lock_);

 Result:=do_sema_b_release(_c^.sema_q,relCnt,_c^.waiters_q_lock_,_c^.value_q);

 //Writeln('<4_pthread_cond_broadcast:',HexStr(_c),':',_c^.name);
end;

procedure cleanup_wait(arg:Pointer); SysV_ABI_CDecl;
const
 INT_MAX=High(Integer);
var
 n,r:Integer;
 ch:psCondWaitHelper;
 _c:pthread_cond;
begin
 if (arg=nil) then Exit;
 ch:=psCondWaitHelper(arg);
 _c:=ch^.c;

 SwEnterCriticalSection(_c^.waiters_count_lock_);

 n:=_c^.waiters_count_unblock_;
 if (n<>0) then
 begin
  Dec(_c^.waiters_count_unblock_);
 end else
 if (((INT_MAX/2)-1)=_c^.waiters_count_gone_) then
 begin

  Inc(_c^.waiters_count_gone_);

  r:=do_sema_b_wait(_c^.sema_b,nil,_c^.waiters_b_lock_,_c^.value_b);

  if (r<>0) then
  begin
   System.LeaveCriticalSection(_c^.waiters_count_lock_);
   ch^.r^:=r;
   Exit;
  end;

  Dec(_c^.waiters_count_,_c^.waiters_count_gone_);

  r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);

  if (r<>0) then
  begin
   System.LeaveCriticalSection(_c^.waiters_count_lock_);
   ch^.r^:=r;
   Exit;
  end;

  _c^.waiters_count_gone_:=0;
 end else
 begin
  Inc(_c^.waiters_count_gone_);
 end;

 System.LeaveCriticalSection(_c^.waiters_count_lock_);

 if (n=1) then
 begin
  r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);

  if (r<>0) then
  begin
   ch^.r^:=r;
   Exit;
  end;

 end;

 r:=ps4_pthread_mutex_lock(ch^.external_mutex);

 if (r<>0) then
 begin
  ch^.r^:=r;
 end;
end;

function pthread_cond_wait(pCond:p_pthread_cond;pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
var
 ch:sCondWaitHelper;
 r:Integer;
 _c:pthread_cond;
Label
 tryagain;
begin
 if (pCond=nil) then Exit(EINVAL);

 _c:=pCond^;
 if (_c=PTHREAD_COND_INITIALIZER) then
 begin
  r:=cond_static_init(pCond);
  if (r<>0) and (r<>EBUSY) then Exit(r);
  _c:=pCond^;
 end else
 if not safe_test(_c^.valid,LIFE_COND) then
  Exit(EINVAL);

 //Writeln('>pthread_cond_wait:',HexStr(_c),':',_c^.name);

 tryagain:
 r:=do_sema_b_wait(_c^.sema_b,nil,_c^.waiters_b_lock_,_c^.value_b);
 if (r<>0) then Exit(r);

 if (System.TryEnterCriticalSection(_c^.waiters_count_lock_)=0) then
 begin
  r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
  if (r<>0) then
  begin
   //Writeln('<1_pthread_cond_wait:',HexStr(_c),':',_c^.name);
   Exit(r);
  end;
  NtYieldExecution;
  goto tryagain;
 end;

 Inc(_c^.waiters_count_);

 LeaveCriticalSection(_c^.waiters_count_lock_);

 r:=do_sema_b_release (_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
 if (r<>0) then
 begin
  //Writeln('<2_pthread_cond_wait:',HexStr(_c),':',_c^.name);
  Exit(r);
 end;

 ch.c:=_c;
 ch.r:=@r;
 ch.external_mutex:=pMutex;
 //pthread_cleanup_push(cleanup_wait, (void *) &ch);

 r:=ps4_pthread_mutex_unlock(pMutex);

 if (r=0) then
 begin
  r:=do_sema_b_wait(_c^.sema_q,nil,_c^.waiters_q_lock_,_c^.value_q);
 end;

 cleanup_wait(@ch);
 //pthread_cleanup_pop(1);

 //Writeln('<3_pthread_cond_wait:',HexStr(_c),':',_c^.name);

 Result:=r;
end;

function pthread_cond_timedwait_impl(c:p_pthread_cond;m:p_pthread_mutex;pTimeout:PQWORD):Integer;
var
 ch:sCondWaitHelper;
 r:Integer;
 _c:pthread_cond;
Label
 tryagain;
begin
 if (c=nil) then Exit(EINVAL);

 _c:=c^;
 if (_c=PTHREAD_COND_INITIALIZER) then
 begin
  r:=cond_static_init(c);
  if (r<>0) and (r<>EBUSY) then Exit(r);
  _c:=c^;
 end else
 if not safe_test(_c^.valid,LIFE_COND) then
  Exit(EINVAL);

 //Writeln('>pthread_cond_timedwait_impl:',HexStr(_c),':',_c^.name);

 tryagain:
 r:=do_sema_b_wait(_c^.sema_b,nil,_c^.waiters_b_lock_,_c^.value_b);
 if (r<>0) then Exit(r);

 if (System.TryEnterCriticalSection(_c^.waiters_count_lock_)=0) then
 begin
  r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
  if (r<>0) then Exit(r);
  NtYieldExecution;
  goto tryagain;
 end;

 Inc(_c^.waiters_count_);

 System.LeaveCriticalSection(_c^.waiters_count_lock_);

 r:=do_sema_b_release(_c^.sema_b,1,_c^.waiters_b_lock_,_c^.value_b);
 if (r<>0) then Exit(r);

 ch.c:=_c;
 ch.r:=@r;
 ch.external_mutex:=m;
 //pthread_cleanup_push(cleanup_wait, (void *) &ch);

 r:=ps4_pthread_mutex_unlock(m);

 if (r=0) then
 begin
  r:=do_sema_b_wait(_c^.sema_q,pTimeout,_c^.waiters_q_lock_,_c^.value_q);
 end;

 cleanup_wait(@ch);
 //pthread_cleanup_pop(1);

 //Writeln('<pthread_cond_timedwait_impl:',HexStr(_c),':',_c^.name);

 Result:=r;
end;

function ps4_pthread_cond_init(pCond:p_pthread_cond;pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=pthread_cond_init(pCond,pAttr,nil);
 _sig_unlock;
end;

function ps4_pthread_cond_destroy(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=pthread_cond_destroy(pCond);
 _sig_unlock;
end;

function ps4_pthread_cond_signal(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=pthread_cond_signal(pCond);
 _sig_unlock;
end;

function ps4_pthread_cond_broadcast(pCond:p_pthread_cond):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=pthread_cond_broadcast(pCond);
 _sig_unlock;
end;

function ps4_pthread_cond_wait(pCond:p_pthread_cond;pMutex:p_pthread_mutex):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=pthread_cond_wait(pCond,pMutex);
 _sig_unlock;
end;

function ps4_pthread_cond_timedwait(pCond:p_pthread_cond;pMutex:p_pthread_mutex;ptime:Ptimespec):Integer; SysV_ABI_CDecl;
var
 t:QWORD;
begin
 if (ptime=nil) then
 begin
  _sig_lock;
  Result:=pthread_cond_wait(pCond,pMutex);
  _sig_unlock;
 end else
 begin
  t:=_pthread_rel_time_in_ns(ptime^);
  _sig_lock;
  Result:=pthread_cond_timedwait_impl(pCond,pMutex,@t);
  _sig_unlock;
 end;
end;

///////////////////////

function ps4_scePthreadCondattrInit(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
begin
 Result:=px2sce(ps4_pthread_condattr_init(pAttr));
end;

function ps4_scePthreadCondattrDestroy(pAttr:p_pthread_condattr):Integer; SysV_ABI_CDecl;
begin
 Result:=px2sce(ps4_pthread_condattr_destroy(pAttr));
end;

function ps4_scePthreadCondInit(pCond:PScePthreadCond;pAttr:p_pthread_condattr;name:Pchar):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=px2sce(pthread_cond_init(pCond,pAttr,name));
 _sig_unlock;
end;

function ps4_scePthreadCondDestroy(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=px2sce(pthread_cond_destroy(pCond));
 _sig_unlock;
end;

function ps4_scePthreadCondSignal(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=px2sce(pthread_cond_signal(pCond));
 _sig_unlock;
end;

function ps4_scePthreadCondWait(pCond:PScePthreadCond;pMutex:PScePthreadMutex):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=px2sce(pthread_cond_wait(pCond,pMutex));
 _sig_unlock;
end;

//Time to wait (microseconds)
function ps4_scePthreadCondTimedwait(pCond:PScePthreadCond;pMutex:PScePthreadMutex;usec:DWORD):Integer; SysV_ABI_CDecl;
var
 t:QWORD;
begin
 t:=_usec2nsec(usec);
 _sig_lock;
 Result:=px2sce(pthread_cond_timedwait_impl(pCond,pMutex,@t));
 _sig_unlock;
end;

function ps4_scePthreadCondBroadcast(pCond:PScePthreadCond):Integer; SysV_ABI_CDecl;
begin
 _sig_lock;
 Result:=px2sce(pthread_cond_broadcast(pCond));
 _sig_unlock;
end;

end.

