unit kern_sx;

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

interface

uses
 kern_rwlock;

type
 p_sx=^t_sx;
 t_sx=packed record
  n:PChar;
  c:Pointer;
  m:QWORD;
 end;

procedure sx_init(p:p_sx;name:PChar);
function  sx_xlocked(p:p_sx):Boolean;
procedure sx_assert(p:p_sx);
procedure sx_slock(p:p_sx);
procedure sx_xlock(p:p_sx);
procedure sx_sunlock(p:p_sx);
procedure sx_xunlock(p:p_sx);
procedure sx_unlock(p:p_sx);
procedure sx_destroy(p:p_sx);

implementation

procedure sx_init(p:p_sx;name:PChar);
begin
 p^.n:=name;
 p^.c:=nil;
 p^.m:=0;
end;

function sx_xlocked(p:p_sx):Boolean;
begin
 Result:=(PDWORD(@p^.m)[0]=ThreadID) and
         (PDWORD(@p^.m)[1]=2);
end;

procedure sx_assert(p:p_sx);
begin
 Assert(sx_xlocked(p),'sx_assert');
end;

procedure sx_slock(p:p_sx);
begin
 //Writeln('    sx_slock:',HexStr(p),':',p^.n);

 rw_rlock(p^.c);
 PDWORD(@p^.m)[0]:=0;
 PDWORD(@p^.m)[1]:=1;
end;

procedure sx_xlock(p:p_sx);
begin
 //Writeln('    sx_xlock:',HexStr(p),':',p^.n);

 rw_wlock(p^.c);
 PDWORD(@p^.m)[0]:=ThreadID;
 PDWORD(@p^.m)[1]:=2;
end;

procedure sx_sunlock(p:p_sx);
begin
 //Writeln('  sx_sunlock:',HexStr(p),':',p^.n);

 rw_runlock(p^.c);
end;

procedure sx_xunlock(p:p_sx);
begin
 //Writeln('  sx_xunlock:',HexStr(p),':',p^.n);

 Assert(PDWORD(@p^.m)[0]=ThreadID,'sx_unlock');

 PDWORD(@p^.m)[0]:=0;
 PDWORD(@p^.m)[1]:=0;

 rw_wunlock(p^.c);
end;

procedure sx_unlock(p:p_sx);
begin
 //Writeln(' sx_unlock:',HexStr(p),':',p^.n);

 case PDWORD(@p^.m)[1] of
  1:rw_runlock(p^.c);
  2:
    begin
     Assert(PDWORD(@p^.m)[0]=ThreadID,'sx_unlock');

     PDWORD(@p^.m)[0]:=0;
     PDWORD(@p^.m)[1]:=0;

     rw_wunlock(p^.c);
    end;
  else
    Assert(false,'sx_unlock');
 end;
end;

procedure sx_destroy(p:p_sx);
begin
 //
end;

end.

