unit _umtx;

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

interface

type
 p_umtx=^umtx;
 umtx=packed record
  u_owner   :QWORD;                // Owner of the mutex
 end;

 p_umutex=^umutex;
 umutex=packed record
  m_owner   :DWORD;                // Owner of the mutex
  m_flags   :DWORD;                // Flags of the mutex
  m_ceilings:array[0..1] of DWORD; // Priority protect ceiling
  m_spare   :array[0..1] of QWORD;
 end;

 p_ucond=^ucond;
 ucond=packed record
  c_has_waiters:DWORD; // Has waiters in kernel
  c_flags      :DWORD; // Flags of the condition variable
  c_clockid    :DWORD; // Clock id
  c_spare      :DWORD; // Spare space
 end;

 p_urwlock=^urwlock;
 urwlock=packed record
  rw_state          :DWORD;
  rw_flags          :DWORD;
  rw_blocked_readers:DWORD;
  rw_blocked_writers:DWORD;
  rw_spare          :array[0..3] of DWORD;
 end;

 p__usem=^_usem;
 _usem=packed record
  _has_waiters:DWORD;
  _count      :DWORD;
  _flags      :DWORD;
 end;

 p_umtx_op_args=^_umtx_op_args;
 _umtx_op_args=packed record
  obj   :Pointer;
  op    :Integer;
  _a    :Integer;
  val   :QWORD;
  uaddr1:Pointer;
  uaddr2:Pointer;
 end;

const
 UMTX_UNOWNED  =$0;
 UMTX_CONTESTED:QWORD=QWORD($8000000000000000);

 USYNC_PROCESS_SHARED=$0001; // Process shared sync objs

 UMUTEX_UNOWNED  =$0;
 UMUTEX_CONTESTED=$80000000;

 UMUTEX_ERROR_CHECK =$0002; // Error-checking mutex
 UMUTEX_PRIO_INHERIT=$0004; // Priority inherited mutex
 UMUTEX_PRIO_PROTECT=$0008; // Priority protect mutex

// urwlock flags
 URWLOCK_PREFER_READER=$0002;

 URWLOCK_WRITE_OWNER  =$80000000;
 URWLOCK_WRITE_WAITERS=$40000000;
 URWLOCK_READ_WAITERS =$20000000;
 URWLOCK_MAX_READERS  =$1fffffff;

 // _usem flags
 SEM_NAMED=$0002;

 // op code for _umtx_op
 UMTX_OP_LOCK             = 0;
 UMTX_OP_UNLOCK           = 1;
 UMTX_OP_WAIT             = 2;
 UMTX_OP_WAKE             = 3;
 UMTX_OP_MUTEX_TRYLOCK    = 4;
 UMTX_OP_MUTEX_LOCK       = 5;
 UMTX_OP_MUTEX_UNLOCK     = 6;
 UMTX_OP_SET_CEILING      = 7;
 UMTX_OP_CV_WAIT          = 8;
 UMTX_OP_CV_SIGNAL        = 9;
 UMTX_OP_CV_BROADCAST     =10;
 UMTX_OP_WAIT_UINT        =11;
 UMTX_OP_RW_RDLOCK        =12;
 UMTX_OP_RW_WRLOCK        =13;
 UMTX_OP_RW_UNLOCK        =14;
 UMTX_OP_WAIT_UINT_PRIVATE=15;
 UMTX_OP_WAKE_PRIVATE     =16;
 UMTX_OP_MUTEX_WAIT       =17;
 UMTX_OP_MUTEX_WAKE       =18; // deprecated
 UMTX_OP_SEM_WAIT         =19;
 UMTX_OP_SEM_WAKE         =20;
 UMTX_OP_NWAKE_PRIVATE    =21;
 UMTX_OP_SEM_SIGNALTO     =22; //Sony extension
 UMTX_OP_MUTEX_WAKE3      =23; //Sony extension
 UMTX_OP_MAX              =24;

 // Flags for UMTX_OP_CV_WAIT
 CVWAIT_CHECK_UNPARKING=$01;
 CVWAIT_ABSTIME        =$02;
 CVWAIT_CLOCKID        =$04;

 UMTX_CHECK_UNPARKING=CVWAIT_CHECK_UNPARKING;

 TYPE_SIMPLE_WAIT  =0;
 TYPE_CV           =1;
 TYPE_SEM          =2;
 TYPE_SIMPLE_LOCK  =3;
 TYPE_NORMAL_UMUTEX=4;
 TYPE_PI_UMUTEX    =5;
 TYPE_PP_UMUTEX    =6;
 TYPE_RWLOCK       =7;
 TYPE_FUTEX        =8;

type
 // Key to represent a unique userland synchronous object
 p_umtx_key=^umtx_key;
 umtx_key=record
  hash  :Integer;
  _type :Integer;
  shared:Integer;
  info  :record
   case byte of
    0:(shared:record
        vm_obj:Pointer; //vm_object
        offset:QWORD;
       end);
    1:(private:record
        vs    :Pointer; //vmspace
        addr  :QWORD;
       end);
    2:(both:record
        a     :Pointer;
        b     :QWORD;
       end);
  end;
 end;

const
 THREAD_SHARE =0;
 PROCESS_SHARE=1;
 AUTO_SHARE   =2;

function umtx_key_match(k1,k2:p_umtx_key):Integer;
function URWLOCK_READER_COUNT(c:DWORD):DWORD;

implementation

function URWLOCK_READER_COUNT(c:DWORD):DWORD;
begin
 Result:=(c and URWLOCK_MAX_READERS);
end;

function umtx_key_match(k1,k2:p_umtx_key):Integer;
begin
 Result:=ord((k1^._type      =k2^._type) and
             (k1^.info.both.a=k2^.info.both.a) and
             (k1^.info.both.b=k2^.info.both.b));
end;

end.

