unit signal;

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

interface

const
 _SIG_WORDS     =4;
 _SIG_MAXSIG    =128;

const
 SIG_BLOCK   =1;
 SIG_UNBLOCK =2;
 SIG_SETMASK =3;

 SIGPROCMASK_OLD         =$0001;
 SIGPROCMASK_PROC_LOCKED =$0002;
 SIGPROCMASK_PS_LOCKED   =$0004;
 SIGPROCMASK_FASTBLK     =$0008;

const
 SIGHUP   =1;       // hangup
 SIGINT   =2;       // interrupt
 SIGQUIT  =3;       // quit
 SIGILL   =4;       // illegal instr. (not reset when caught)
 SIGTRAP  =5;       // trace trap (not reset when caught)
 SIGABRT  =6;       // abort()
 SIGIOT   =SIGABRT; // compatibility
 SIGEMT   =7;       // EMT instruction
 SIGFPE   =8;       // floating point exception
 SIGKILL  =9;       // kill (cannot be caught or ignored)
 SIGBUS   =10;      // bus error
 SIGSEGV  =11;      // segmentation violation
 SIGSYS   =12;      // non-existent system call invoked
 SIGPIPE  =13;      // write on a pipe with no one to read it
 SIGALRM  =14;      // alarm clock
 SIGTERM  =15;      // software termination signal from kill
 SIGURG   =16;      // urgent condition on IO channel
 SIGSTOP  =17;      // sendable stop signal not from tty
 SIGTSTP  =18;      // stop signal from tty
 SIGCONT  =19;      // continue a stopped process
 SIGCHLD  =20;      // to parent on child stop or exit
 SIGTTIN  =21;      // to readers pgrp upon background tty read
 SIGTTOU  =22;      // like TTIN if (tp->t_local&LTOSTOP)
 SIGIO    =23;      // input/output possible signal
 SIGXCPU  =24;      // exceeded CPU time limit
 SIGXFSZ  =25;      // exceeded file size limit
 SIGVTALRM=26;      // virtual time alarm
 SIGPROF  =27;      // profiling time alarm
 SIGWINCH =28;      // window size changes
 SIGINFO  =29;      // information request
 SIGUSR1  =30;      // user defined signal 1
 SIGUSR2  =31;      // user defined signal 2
 SIGTHR   =32;      // reserved by thread library.
 SIGLWP   =SIGTHR;
 SIGCANCEL=SIGTHR;

 NSIG=32;

 SIGRTMIN=65;
 SIGRTMAX=126;

 SIG_DFL  = 0; //default
 SIG_IGN  = 1; //ignore
 SIG_ERR  =-1;
 SIG_CATCH= 2; //See signalvar.h
 SIG_HOLD = 3;

 SA_ONSTACK   =$0001; // take signal on signal stack
 SA_RESTART   =$0002; // restart system call on signal return
 SA_RESETHAND =$0004; // reset to SIG_DFL when taking signal
 SA_NODEFER   =$0010; // don't mask the signal we're delivering
 SA_NOCLDWAIT =$0020; // don't keep zombies around
 SA_SIGINFO   =$0040; // signal handler with SA_SIGINFO args

 SI_NOINFO =0;       // No signal info besides si_signo.
 SI_USER   =$10001;  // Signal sent by kill().
 SI_QUEUE  =$10002;  // Signal sent by the sigqueue().
 SI_TIMER  =$10003;  // Signal generated by expiration of a timer set by timer_settime().
 SI_ASYNCIO=$10004;  // Signal generated by completion of an asynchronous I/O request.
 SI_MESGQ  =$10005;  // Signal generated by arrival of a message on an empty message queue.
 SI_KERNEL =$10006;
 SI_LWP    =$10007;  // Signal sent by thr_kill

 //mc_fpformat
 _MC_FPFMT_NODEV=$10000; // device not present or configured
 _MC_FPFMT_XMM  =$10002;

 //mc_ownedfp
 _MC_FPOWNED_NONE=$20000; // FP state not used
 _MC_FPOWNED_FPU =$20001; // FP state came from FPU
 _MC_FPOWNED_PCB =$20002; // FP state came from PCB

 //mc_flags bits. Shall be in sync with TF_XXX.
 _MC_HASSEGS    =$1; //mc_ds,mc_es,mc_fs,mc_gs
 _MC_HASBASES   =$2; //mc_fsbase,mc_gsbase
 _MC_HASFPXSTATE=$4; //xmm
 _MC_FLAG_MASK  =(_MC_HASSEGS or _MC_HASBASES or _MC_HASFPXSTATE);

 TF_HASSEGS    =$1;
 TF_HASBASES   =$2;
 TF_HASFPXSTATE=$4;

type
 p_sigset_t=^sigset_t;
 sigset_t=packed record //16
  Case Byte of
   0:(bits:array[0.._SIG_WORDS-1] of DWORD);
   1:(qwords:array[0..(_SIG_WORDS div 2)-1] of QWORD);
 end;
 {$IF sizeof(sigset_t)<>16}{$STOP sizeof(sigset_t)<>16}{$ENDIF}

 sigval=packed record //8
  Case Byte of
   // Members as suggested by Annex C of POSIX 1003.1b.
   0:(sival_int:Integer);
   1:(sival_ptr:Pointer);
   //6.0 compatibility
   2:(sigval_int:Integer);
   3:(sigval_ptr:Pointer);
 end;
 {$IF sizeof(sigval)<>8}{$STOP sizeof(sigval)<>8}{$ENDIF}

 p_sigevent=^sigevent;
 sigevent=packed record
  sigev_notify:Integer; //Notification type
  sigev_signo :Integer; //Signal number
  sigev_value :sigval;  //Signal value

  _sigev_un:packed record
   Case Byte of
    0:(_threadid:Integer); //__lwpid_t
    1:(_sigev_thread:packed record
        _function :Pointer; //void (*_function)(union sigval);
        _attribute:Pointer; //pthread_attr_t
       end);
    2:(__spare__:array[0..7] of QWORD);
  end;

 end;

 p_siginfo_t=^siginfo_t;
 siginfo_t=packed record //80
  si_signo:Integer; //signal number
  si_errno:Integer; //errno association
  {
   * Cause of signal, one of the SI_ macros or signal-specific
   * values, i.e. one of the FPE_... values for SIGFPE.  This
   * value is equivalent to the second argument to an old-style
   * FreeBSD signal handler.
  }
  si_code  :Integer;  // signal code           SI_USER
  si_pid   :Integer;  // sending process
  si_uid   :DWORD;    // sender's ruid
  si_status:Integer;  // exit value
  si_addr  :Pointer;  // faulting instruction
  si_value :sigval;   // signal value

  _reason:packed record
   Case Byte of
    0:(_fault:packed record
        _trapno:Integer; // machine specific trap code
       end);
    1:(_timer:packed record
        _timerid:Integer;
        _overrun:Integer;
       end);
    2:(_mesgq:packed record
        _mqd:Integer;
       end);
    3:(_poll:packed record
       _band:QWORD;        // band event for SIGPOLL
      end);
    4:(__spare__:packed record
        __spare1__:QWORD;
        __spare2__:array[0..7] of Integer;
       end);
  end;

 end;
 {$IF sizeof(siginfo_t)<>80}{$STOP sizeof(siginfo_t)<>80}{$ENDIF}

 sa_handler  =procedure(sig,code:Integer;ctx:Pointer); SysV_ABI_CDecl;
 sa_sigaction=procedure(sig:Integer;info:p_siginfo_t;ctx:Pointer); SysV_ABI_CDecl;

 sig_t=sa_handler;

 p_sigaction_t=^sigaction_t;
 sigaction_t=packed record //28

  u:packed record        // signal handler
   Case Byte of
    0:(code:Ptrint);               //SIG_DFL
    1:(sa_handler:sa_handler);     //void (*__sa_handler)(int);
    2:(sa_sigaction:sa_sigaction); //void (*__sa_sigaction)(int, struct __siginfo *, void *); (sa_flags and SA_SIGINFO)<>0
  end;

  sa_flags:Integer;  //SA_SIGINFO
  sa_mask :sigset_t; //signal mask to apply     (signal mask inside signal)
 end;
 {$IF sizeof(sigaction_t)<>28}{$STOP sizeof(sigaction_t)<>28}{$ENDIF}

 sigaltstack=packed record
  ss_sp   :Pointer; //signal stack base
  ss_size :size_t;  //signal stack length SIGSTKSZ
  ss_flags:Integer; //SS_DISABLE and/or SS_ONSTACK
  _align  :Integer;
 end;

 p_stack_t=^stack_t;
 stack_t=sigaltstack;
 {$IF sizeof(stack_t)<>24}{$STOP sizeof(stack_t)<>24}{$ENDIF}

const
 SA_NOCLDSTOP=$0008;   // do not generate SIGCHLD on child stop

 SS_ONSTACK  =$0001;   // take signal on alternate stack
 SS_DISABLE  =$0004;   // disable taking signals on alternate stack
 MINSIGSTKSZ =(512*4); // minimum stack size
 SIGSTKSZ    =(MINSIGSTKSZ+32768); // recommended stack size

// uc_flags
 _UC_SIGMASK=$01;  // valid uc_sigmask
 _UC_STACK  =$02;  // valid uc_stack
 _UC_CPU    =$04;  // valid GPR context in uc_mcontext
 _UC_FPU    =$08;  // valid FPU context in uc_mcontext

function _SIG_IDX(sig:Integer):DWORD;        inline;
function _SIG_VALID(sig:Integer):Boolean;    inline;
function _SIG_VALID_32(sig:Integer):Boolean; inline;
function _SIG_WORD(sig:Integer):DWORD; inline;
function _SIG_BIT(sig:Integer):DWORD; inline;

procedure ps_mtx_lock;   external;
procedure ps_mtx_unlock; external;

function  sigdeferstop:Integer; external;
procedure sigallowstop; external;

Function  sigonstack(sp:size_t):Integer; external;
Function  cursig(td:Pointer;stop_allowed:Integer):Integer; external;
procedure tdsignal(td:Pointer;sig:Integer); external;
procedure sigexit(td:Pointer;sig:Integer); external;

procedure ast; external;

Function  kern_sigprocmask(td:Pointer;
                           how:Integer;
                           _set:p_sigset_t;
                           oset:p_sigset_t;
                           flags:Integer
                          ):Integer; external;

function _get_sig_str(signum:Integer):RawByteString;

implementation

function _SIG_IDX(sig:Integer):DWORD; inline;
begin
 Result:=sig-1;
end;

function _SIG_VALID(sig:Integer):Boolean; inline;
begin
 Result:=(sig<=_SIG_MAXSIG) and (sig>0);
end;

function _SIG_VALID_32(sig:Integer):Boolean; inline;
begin
 Result:=(sig<=32) and (sig>0);
end;

function _SIG_WORD(sig:Integer):DWORD; inline;
begin
 Result:=_SIG_IDX(sig) shr 5;
end;

function _SIG_BIT(sig:Integer):DWORD; inline;
begin
 Result:=1 shl (_SIG_IDX(sig) and 31);
end;

function _get_sig_str(signum:Integer):RawByteString;
begin
 case signum of
  SIGHUP   :Result:='SIGHUP';
  SIGINT   :Result:='SIGINT';
  SIGQUIT  :Result:='SIGQUIT';
  SIGILL   :Result:='SIGILL';
  SIGTRAP  :Result:='SIGTRAP';
  SIGABRT  :Result:='SIGABRT';
  SIGEMT   :Result:='SIGEMT';
  SIGFPE   :Result:='SIGFPE';
  SIGKILL  :Result:='SIGKILL';
  SIGBUS   :Result:='SIGBUS';
  SIGSEGV  :Result:='SIGSEGV';
  SIGSYS   :Result:='SIGSYS';
  SIGPIPE  :Result:='SIGPIPE';
  SIGALRM  :Result:='SIGALRM';
  SIGTERM  :Result:='SIGTERM';
  SIGURG   :Result:='SIGURG';
  SIGSTOP  :Result:='SIGSTOP';
  SIGTSTP  :Result:='SIGTSTP';
  SIGCONT  :Result:='SIGCONT';
  SIGCHLD  :Result:='SIGCHLD';
  SIGTTIN  :Result:='SIGTTIN';
  SIGTTOU  :Result:='SIGTTOU';
  SIGIO    :Result:='SIGIO';
  SIGXCPU  :Result:='SIGXCPU';
  SIGXFSZ  :Result:='SIGXFSZ';
  SIGVTALRM:Result:='SIGVTALRM';
  SIGPROF  :Result:='SIGPROF';
  SIGWINCH :Result:='SIGWINCH';
  SIGINFO  :Result:='SIGINFO';
  SIGUSR1  :Result:='SIGUSR1';
  SIGUSR2  :Result:='SIGUSR2';
  SIGTHR   :Result:='SIGTHR';
  else
   Str(signum,Result);
  end;
end;

end.


