unit signalvar;

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

interface

uses
 kern_mtx,
 signal;

type
 sigacts=packed record
  ps_sigact    :array[0.._SIG_MAXSIG-1] of sig_t;
  ps_catchmask :array[0.._SIG_MAXSIG-1] of sigset_t;
  ps_sigonstack:sigset_t;
  ps_sigintr   :sigset_t;
  ps_sigreset  :sigset_t;
  ps_signodefer:sigset_t;
  ps_siginfo   :sigset_t;
  ps_sigignore :sigset_t;
  ps_sigcatch  :sigset_t;
  ps_mtx       :mtx;
  ps_flag      :Integer;
 end;

var
 p_sigacts:sigacts;

const
 PS_NOCLDWAIT=$0001; // No zombies if child dies
 PS_NOCLDSTOP=$0002; // No SIGCHLD when children stop.
 PS_CLDSIGIGN=$0004; // The SIGCHLD handler is SIG_IGN.

 SIG_CATCH=2;

type
 p_ksiginfo=^ksiginfo_t;
 p_sigqueue=^sigqueue_t;

 ksiginfo_list=packed record
  pFirst:p_ksiginfo;
  pLast :PPointer;
 end;

 ksiginfo_entry=packed record
  pNext:p_ksiginfo;
  pPrev:PPointer;
 end;

 ksiginfo_t=packed record
  ksi_link :ksiginfo_entry;
  ksi_info :siginfo_t;
  ksi_flags:Integer;
  _align   :Integer;
  ksi_sigq :p_sigqueue;
 end;

 sigqueue_t=packed record
  sq_signals:sigset_t;
  sq_kill   :sigset_t;
  sq_list   :ksiginfo_list;
  sq_flags  :Integer;
 end;

const
 //bits for ksi_flags
 KSI_TRAP    =$01; // Generated by trap.
 KSI_EXT     =$02; // Externally managed ksi.
 KSI_INS     =$04; // Directly insert ksi, not the copy
 KSI_SIGQ    =$08; // Generated by sigqueue, might ret EGAIN.
 KSI_HEAD    =$10; // Insert into head, not tail.
 KSI_COPYMASK=(KSI_TRAP or KSI_SIGQ);

 // Flags for ksi_flags
 SQ_INIT=$01;

 SIG_STOP_ALLOWED    =100;
 SIG_STOP_NOT_ALLOWED=101;

function  SIGACTION      (sig:Integer):sig_t; inline;
procedure SIGADDSET      (p:p_sigset_t;signo:Integer); inline;
procedure SIGDELSET      (p:p_sigset_t;signo:Integer); inline;
procedure SIGEMPTYSET    (p:p_sigset_t); inline;
procedure SIGFILLSET     (p:p_sigset_t); inline;
function  SIGISMEMBER    (p:p_sigset_t;signo:Integer):Boolean; inline;
function  SIGISEMPTY     (p:p_sigset_t):Boolean; inline;
function  SIGNOTEMPTY    (p:p_sigset_t):Boolean; inline;
function  SIGSETEQ       (p1,p2:p_sigset_t):Boolean; inline;
function  SIGSETNEQ      (p1,p2:p_sigset_t):Boolean; inline;
procedure SIGSETOR       (p1,p2:p_sigset_t); inline;
procedure SIGSETAND      (p1,p2:p_sigset_t); inline;
procedure SIGSETNAND     (p1,p2:p_sigset_t); inline;
procedure SIGSETLO       (p1,p2:p_sigset_t); inline;
procedure SIG_CANTMASK   (p:p_sigset_t); inline;
procedure SIG_STOPSIGMASK(p:p_sigset_t); inline;
procedure SIG_CONTSIGMASK(p:p_sigset_t); inline;

function  sigsetmasked(p,mask:p_sigset_t):Boolean; inline;
function  sig_ffs(p:p_sigset_t):Integer; inline;

procedure ksiginfo_init(ksi:p_ksiginfo); inline;
procedure ksiginfo_init_trap(ksi:p_ksiginfo); inline;
procedure ksiginfo_copy(src,dst:p_ksiginfo); inline;
procedure ksiginfo_set_sigev(dst:p_ksiginfo;sigev:p_sigevent); inline;

implementation

function SIGACTION(sig:Integer):sig_t; inline;
begin
 Result:=p_sigacts.ps_sigact[_SIG_IDX(sig)];
end;

procedure SIGADDSET(p:p_sigset_t;signo:Integer); inline;
begin
 p^.bits[_SIG_WORD(signo)]:=p^.bits[_SIG_WORD(signo)] or _SIG_BIT(signo);
end;

procedure SIGDELSET(p:p_sigset_t;signo:Integer); inline;
begin
 p^.bits[_SIG_WORD(signo)]:=p^.bits[_SIG_WORD(signo)] and (not _SIG_BIT(signo));
end;

procedure SIGEMPTYSET(p:p_sigset_t); inline;
begin
 p^.qwords[0]:=0;
 p^.qwords[1]:=0;
end;

procedure SIGFILLSET(p:p_sigset_t); inline;
begin
 p^.qwords[0]:=QWORD(-1);
 p^.qwords[1]:=QWORD(-1);
end;

function SIGISMEMBER(p:p_sigset_t;signo:Integer):Boolean; inline;
begin
 Result:=(p^.bits[_SIG_WORD(signo)] and _SIG_BIT(signo))<>0;
end;

function SIGISEMPTY(p:p_sigset_t):Boolean; inline;
begin
 Result:=(p^.qwords[0]=0) and (p^.qwords[1]=0)
end;

function SIGNOTEMPTY(p:p_sigset_t):Boolean; inline;
begin
 Result:=not SIGISEMPTY(P);
end;

function SIGSETEQ(p1,p2:p_sigset_t):Boolean; inline;
begin
 Result:=(p1^.qwords[0]=p2^.qwords[0]) and (p1^.qwords[1]=p2^.qwords[1]);
end;

function SIGSETNEQ(p1,p2:p_sigset_t):Boolean; inline;
begin
 Result:=not SIGSETEQ(p1,p2);
end;

procedure SIGSETOR(p1,p2:p_sigset_t); inline;
begin
 p1^.qwords[0]:=p1^.qwords[0] or p2^.qwords[0];
 p1^.qwords[1]:=p1^.qwords[1] or p2^.qwords[1];
end;

procedure SIGSETAND(p1,p2:p_sigset_t); inline;
begin
 p1^.qwords[0]:=p1^.qwords[0] and p2^.qwords[0];
 p1^.qwords[1]:=p1^.qwords[1] and p2^.qwords[1];
end;

procedure SIGSETNAND(p1,p2:p_sigset_t); inline;
begin
 p1^.qwords[0]:=p1^.qwords[0] and (not p2^.qwords[0]);
 p1^.qwords[1]:=p1^.qwords[1] and (not p2^.qwords[1]);
end;

procedure SIGSETLO(p1,p2:p_sigset_t); inline;
begin
 p1^.bits[0]:=p2^.bits[0];
end;

procedure SIG_CANTMASK(p:p_sigset_t); inline;
begin
 SIGDELSET(p,SIGKILL);
 SIGDELSET(p,SIGSTOP);
end;

procedure SIG_STOPSIGMASK(p:p_sigset_t); inline;
begin
 SIGDELSET(p,SIGSTOP);
 SIGDELSET(p,SIGTSTP);
 SIGDELSET(p,SIGTTIN);
 SIGDELSET(p,SIGTTOU);
end;

procedure SIG_CONTSIGMASK(p:p_sigset_t); inline;
begin
 SIGDELSET(p,SIGCONT)
end;

function sigsetmasked(p,mask:p_sigset_t):Boolean; inline;
begin
 Result:=((p^.qwords[0] and (not mask^.qwords[0]))<>0) or
         ((p^.qwords[1] and (not mask^.qwords[1]))<>0);
end;

function sig_ffs(p:p_sigset_t):Integer; inline;
begin
 Result:=0;
 if (p^.qwords[0]<>0) then Result:=BsfQWord(p^.qwords[0])+1;
 if (p^.qwords[1]<>0) then Result:=BsfQWord(p^.qwords[1])+65;
end;

procedure ksiginfo_init(ksi:p_ksiginfo); inline;
begin
 ksi^:=Default(ksiginfo_t);
end;

procedure ksiginfo_init_trap(ksi:p_ksiginfo); inline;
begin
 ksi^:=Default(ksiginfo_t);
 ksi^.ksi_flags:=KSI_TRAP;
end;

procedure ksiginfo_copy(src,dst:p_ksiginfo); inline;
begin
 dst^.ksi_info :=src^.ksi_info;
 dst^.ksi_flags:=src^.ksi_flags and KSI_COPYMASK;
end;

procedure ksiginfo_set_sigev(dst:p_ksiginfo;sigev:p_sigevent); inline;
begin
 dst^.ksi_info.si_signo:=sigev^.sigev_signo;
 dst^.ksi_info.si_value:=sigev^.sigev_value;
end;


end.

