#ifndef _SYS_SIGNAL_H
#define _SYS_SIGNAL_H
/*
 * The <sys/signal.h> header defines items which are specific to
 * the QDOS implementation of signals.
 *
 * AMENDMENT HISTORY
 * ~~~~~~~~~~~~~~~~~
 *  24 Aug 95   RD    - First version to support Richard Zlidlicky signal 
 *                      handling routines.
 *
 *  20 Sep 95   DJW   - Moved to this file all definitions that were previously
 *                      in the signal.h file protected by the __LIBRARY__
 *                      definition as this is a cleaner way of doing it.
 */

#ifndef _SIGNAL_H
#include <signal.h>
#endif

#ifdef __STDC__
#define _P_(params) params
#else
#define _P_(params)
#endif


#ifndef _SIGSET_T
typedef unsigned long sigset_t;
#define _SIGSET_T
#endif


/* signal priority bitfields */
/* receiving job */
struct SIG_PRIOR_R {
          unsigned norm :3;   /* to interrupt job in normal state       */
          unsigned susp :3;   /*                ... waiting for IO      */
          unsigned wfio :3;   /*                ...  ...        job     */
          unsigned wfjob:3;   /*         .... a suspended job           */
     /* special bits */
          unsigned req_sigstack:1;     
                              /* use extra allocated sigstack (not yet) */
     /* to cope with progs that do untidy things with the stack         */
          unsigned reserved : 19;
                              /* other bits reserved, pad to lonword    */
          };

/* sending job */
struct SIG_PRIOR_S {
          unsigned norm : 3;  /* to interrupt job in normal state       */
          unsigned susp : 3;  /*                ... waiting for IO      */
          unsigned wfio : 3;  /*                ...  ...        job     */
          unsigned wfjob: 3;  /*         .... a suspended job           */
     /* special bits */
          unsigned df_susp   : 1;
                              /* defer sig if susp and priority too small*/
          unsigned df_wfio  : 1;
                              /*        ...   wfio                      */
          unsigned df_wfjob  : 1;
                              /*              wfjob                     */
          unsigned retry_sigsend :1;   
                              /* retry sigsending for tmout, blocks     */
                              /* sigsending job                         */
          unsigned reserved  : 16;      /* make sure it pads to longword */
          };

/* message struct for sending signals */
struct SIG_MSG {
         unsigned long magic;       /* '%MSG' */
         unsigned long len;
         unsigned short type;
         unsigned short txi;
         unsigned long jobid,signr;
         struct SIG_PRIOR_S prio;
         unsigned long uval;
         };

/* message struct for timer event control */
struct TMR_MSG {
         unsigned long magic;
         unsigned long len;
         unsigned short type;
         unsigned short txi;
         unsigned long jobid,signr;
         struct SIG_PRIOR_S prio;
         unsigned long uval;
         unsigned long t_evid;      /* event id, unique per job */
         unsigned long t_ticks;
         unsigned long t_int;
         };
#define M_SIG 0
#define M_TIMER 1
#define MT_TICKS 0         /* time unit */
#define MT_SECS  1
#define EV_ALARM 1         /* event id for alarm */


/* QDOS simple sighandler structure */
struct QDOS_SIGH {
          unsigned short m1;            /* 0x4afc */
          unsigned  long m2;            /* '%SIG' */
          void (*sighandler)(void);     /* args passed in registers */
          char * stackmin;
          struct SIG_PRIOR_R priority;  /* longword */
          };

/* more complicated sighandler structure */
/* used by c68 */
struct QDOS_CSIGH {
         unsigned short m1;             /* 0x4afc */
         unsigned long m2;             /* %CSG   */
         unsigned nsig;

         void (***  curr) (int) ;   /* current table *       */
         void (***  def) (int)  ;   /* default table *       */

         sigset_t **samask;

         unsigned short prot_id;
         union {unsigned short levl; 
                unsigned short **plevl;} hprotlevel;

         unsigned short stack_id;
         char *   stackmin;

         unsigned short pri_id;
         union {struct SIG_PRIOR_R prio;
                struct SIG_PRIOR_R **pprio; } priority;

         void *siginfo;
         int (*sigvec)(int, ...);   /* vector for sigaction() etc. */

/* some status info */
         unsigned short cprotlevel;
         unsigned short defer;
         unsigned short activ;

         long **uval;
         sigset_t block;
         sigset_t pending;
         sigset_t resethandler;
         };


struct SREGS {
          datareg_t d0,d1,d2;
          addreg_t    a0,a1;
          };


/* SIGNATURE describes state in which job was interrupted, might
   be used to restart io, resync job wait  etc..   */

#define  SGN_NORM 0           /* signal rcved during normal execution     */
#define  SGN_WFIO 1           /* may have interrupted io call,            */
                              /*                  check D0 for err.nc     */
#define  SGN_WFJB 2           /* ..... interrupted while waiting for job  */
#define  SGN_SUSP 3           /* ..... some other suspension              */
#define  SGN_RAISE 4          /* raise() or checksig call                 */



/* saved state of job left on stack, by QDOS_SIGH handlers */

struct SIGSVB {
          void (*sig_clup)(void);   /* cleanup routine, usually           */
                                    /* called by RTS. (a7->struct SIGSVB) */
          short signature;
          long  sf1,sf2;            /* signature specific, reserved       */
          datareg_t d4,d5,d6;       /* saved registers    */
          addreg_t  a4,a5,a7;

          short sr;
          long  ret_addr;           /* interrupted here */
          };

/* saved job context for QDOS_CSIGH type handlers */

struct ESVB {
         struct SIGSVB sigsvb;
         sigset_t oblock;           /* saved block mask */
         long ohand;                /* saved handler */
         long signr;
         struct QDOS_CSIG *hptr;
         long uval;
         datareg_t  d0,d1,d2;       /* extra save registers */
         addreg_t   a0,a1;
};

/*extern struct QDOS_SIGH _sigstruct; */    /* QDOS level handler struct */
extern struct QDOS_CSIGH _sigh;



typedef short SigProtState_t;           /* */
#define sigmask(i)  ((sigset_t)(1 << (i-1)))

#ifdef OLD
struct C_HANDLER {
  unsigned       nsig;
  sigset_t       sigpend;
  sigset_t       sigblock;
  SigProtState_t sigprotect;
  sigset_t       sigreset;


   void (*(*  sigcurrent)[_NSIG+1]) (int) ;
   void (*(*  sigdefault)[_NSIG+1]) (int) ;
  sigset_t (*sigsamask)[_NSIG+1] ;
};

extern struct C_HANDLER _sigcontrol;
extern void (* __sigcurrent[_NSIG+1])(int);
extern void (* __sigdefault[_NSIG+1])(int);
extern sigset_t __sigsamask[_NSIG+1];
#endif /* OLD */


extern chanid_t _sigch;     /* standard chan for signal send&receive */

#ifdef DEBUG
extern chanid_t _sigdebugch;
extern int _sigdebug;
extern int sigprintf();
#endif

extern long _spbase;
extern long _stackmargin;


/* some defaults */
extern struct SIG_PRIOR_R _defsigrp;  /* default receive priority */
extern struct SIG_PRIOR_S _defsigsp;  /*         send             */
extern struct SIG_PRIOR_S _defsigskp; /*         send SIGKILL     */

#ifdef OLD
/* default signal() flags masks     */
#define SIGF_BLK  0x1      /* set sa_mask to sigmask(signo)       */
#define SIGF_RES  0x2      /* equiv to SA_RESETHAND               */
extern long   _defsigblock;      /* default behaviour of signal() */
void _sigwrap(void);          /* default sighandler for c progs, takes    */
/* args in d4,d5,a4 push them on stack and call _sig_handler()  Function  */
void checksig(void);          /* call to check & raise pending signals    */
void _call_sighandler(int);   /* call sighandler directly, does all checks */
#endif OLD

int sendsig(chanid_t ,jobid_t ,long ,struct SIG_PRIOR_S ,long );

void _init_sigrec(void);      /* open _sigch, init handler */

int set_timer_event(struct TMR_MSG *);



/* macros for protecting sensible calls */

#define SIGPROTSTATE_PROTECTED    ((char) 1)
#define SIGPROTSTATE_UNPROTECTED  ((char) 0)

#define SAVESIGPROTSTATE(var)   {var = _sigcontrol.sigprotect;}
#define SETSIGPROTSTATE(state)  {_sigcontrol.sigprotect = state;}

/* call '{ (void) fun; }' in protected mode  */

#define SYSCALLV(fun)  {SigProtState_t _SCi_; SAVESIGPROTSTATE(_SCi_);\
         SETSIGPROTSTATE(SIGPROTSTATE_PROTECTED); \
         (void) fun ;\
         SETSIGPROTSTATE(_SCi_) ; \
         if(_sigcontrol.sigpend) checksig(); }


/* call '{var=(fun);}' in protected mode       */

#define SYSCALLASSIGN(var,fun) {SigProtState_t _SCi_; SAVESIGPROTSTATE(_SCi_);\
         SETSIGPROTSTATE(SIGPROTSTATE_PROTECTED); \
         var=(fun) ; \
         SETSIGPROTSTATE(_SCi_) ; \
         if(_sigcontrol.sigpend) checksig(); }


/* call '{return (rytpe)(fun);}' in protected mode */

#define SYSCALLRET(fun,rtype)  {rtype _SCr_; SigProtState_t _SCi_; \
         SAVESIGPROTSTATE(_SCi_); SETSIGPROTSTATE(SIGPROTSTATE_PROTECTED)\
         _SCr_=(fun); \
         SETSIGPROTSTATE(_SCi_);\
         if(_sigcontrol.sigpend) checksig();return _SCr_; }


#if 0
/*
 *  Structures internally to maintain signal status
 *  NOTE.  If the _sigcontrol structure changes then the 
 *         _SigSend() assembler routine must be altered.
 */

extern struct _sigcontrol {
    int         count;
    sigset_t    mask;       /* Current signal mask */
    sigset_t    pend;       /* Pending signals */
    sigset_t    block;      /* Block while running signal handler */
    long        alarm;      /* time (QL) of next signal (or 0) */
    void        (*handler[_NSIG+1])_P_((int));
    } _sigcurrent;
extern  void (*_sigdefault [_NSIG+1])_P_((int));


/*
 *  Mask for signals we do not allow to be blocked
 */
#define _SIG_UNBLOCKABLE (SIGABRT | SIGKILL)

/*
 *  Labels within the signal handler
 */
extern char   _SigSend;
extern pid_t  _SigSendPid;
extern long   _SigSendPriority;
extern char * _SigSendAddress;
extern int    _SigSendNum;
extern char   _SigSendEnd;
/*
 *  Internal library routines for signal support
 */
void    _chksig         _P_((void));
void    _sigdie         _P_((int));
void    _sigignore      _P_((int));
void    _sigreport      _P_((int));
void    (*_signal       _P_((int , void (*)_P_((int)))))_P_((int));
#endif


extern  int    _CheckSig  _P_((void));
extern  void   _onsigkill _P_((int));    /* default action for SIGKILL */

/* 
 *  default actions for signals
 */
#define _SIG_TERMINATE  0
#define _SIG_ABNORMAL   1
#define _SIG_IGNORE     2
#define _SIG_STOP       3
#define _SIG_ALARM      4


#define _SIG_TERMINATE 0
#define _SIG_ABNORMAL 1
#define _SIG_IGNORE 2
#define _SIG_STOP 3
#define _SIG_ALARM 4
/*
 *  Mask for signals we do not allow to be blocked
 */
#define _SIG_UNBLOCKABLE  sigmask( SIGKILL )


#ifdef OLD
extern char __inabort;     /* abort patch */
#endif

extern char *     __SigNoMsg;
extern short      __SigNoCnt;
extern sigset_t * __SigSaMask[_NSIG+1];
extern void    (* __SigCurrent[_NSIG+1]) (int);
extern void    (* __SigDefault[_NSIG+1]) (int);
extern long     * __SigUval[_NSIG+1];

extern int _SigNoImp(int, ...);

#endif  /* _SYS_SIGNAL_H */

