unit sys_umtx;

{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}

interface

uses
 time,
 _umtx;

procedure umtx_init(var umtx:umtx); inline;
function  umtx_owner(var umtx:umtx):QWORD; inline;
function  umtx_lock(var umtx:umtx;id:QWORD):Integer; inline;
function  umtx_trylock(var umtx:umtx;id:QWORD):Integer; inline;
function  umtx_timedlock(var umtx:umtx;id:QWORD;timeout:p_timespec):Integer; inline;
function  umtx_unlock(var umtx:umtx;id:QWORD):Integer; inline;
function  umtx_wait(var umtx:umtx;id:QWORD;timeout:p_timespec):Integer; inline;
function  umtx_wake(var umtx:umtx;nr_wakeup:Integer):Integer; inline;

function  _umtx_op_err(obj:Pointer;op:Integer;val:QWORD;uaddr1,uaddr2:Pointer):Integer;

implementation

uses
 errno,
 syscalls,
 trap;

procedure umtx_init(var umtx:umtx); inline;
begin
 umtx.u_owner:=UMTX_UNOWNED;
end;

function umtx_owner(var umtx:umtx):QWORD; inline;
begin
 Result:=umtx.u_owner and (not UMTX_CONTESTED)
end;

function umtx_lock(var umtx:umtx;id:QWORD):Integer; inline;
begin
 Result:=0;
 if (System.InterlockedCompareExchange64(umtx.u_owner,id,UMTX_UNOWNED)=0) then
 begin
  Result:=_umtx_lock(@umtx);
 end;
end;

function umtx_trylock(var umtx:umtx;id:QWORD):Integer; inline;
begin
 Result:=0;
 if (System.InterlockedCompareExchange64(umtx.u_owner,id,UMTX_UNOWNED)=0) then
 begin
  Result:=EBUSY;
 end;
end;

function umtx_timedlock(var umtx:umtx;id:QWORD;timeout:p_timespec):Integer; inline;
begin
 Result:=0;
 if (System.InterlockedCompareExchange64(umtx.u_owner,id,UMTX_UNOWNED)=0) then
 begin
  Result:=_umtx_op(@umtx,UMTX_OP_LOCK,id,nil,timeout)
 end;
end;

function umtx_unlock(var umtx:umtx;id:QWORD):Integer; inline;
begin
 Result:=0;
 if (System.InterlockedCompareExchange64(umtx.u_owner,UMTX_UNOWNED,id)=0) then
 begin
  Result:=_umtx_unlock(@umtx);
 end;
end;

function umtx_wait(var umtx:umtx;id:QWORD;timeout:p_timespec):Integer; inline;
begin
 Result:=_umtx_op(@umtx,UMTX_OP_WAIT,id,nil,timeout)
end;

function umtx_wake(var umtx:umtx;nr_wakeup:Integer):Integer; inline;
begin
 Result:=_umtx_op(@umtx,UMTX_OP_WAKE,nr_wakeup,nil,nil);
end;

function _umtx_op_err(obj:Pointer;op:Integer;val:QWORD;uaddr1,uaddr2:Pointer):Integer; assembler; nostackframe;
asm
 movq  $454,%rax
 call  fast_syscall
end;

end.

