/*static char *SCCSID = "@(#)sigsubr.c	6.4 91/06/13";*/
#define SCCSID  "@(#)sigsubr.c	6.4 91/06/13"

/*
 *      Signals - Signal subroutines in C
 *
 *      This is an OS/2 2.x specific file
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      Created: November 1989 - Kyle Peltonen
 *
 *      MODIFICATION HISTORY
 *      18-Jan-95  Change Team  Defect 108449 - Added XCPT_SIGNAL_APTERM to
 *                              VR32AcknowledgeSignalException to allow
 *                              acknowledge of async process terminate.
 */


#define INCL_TYPES                      /* for basedef.h */
#define INCL_ERRORS                     /* for bseerr.h */
#include <basedef.h>
#define FNO_NUM FNO_SIGSUBR_C
#include <fnotask.h>
#include <osmac.h>
#include <osconst.h>
#include <ostypes.h>
#include <infoseg.h>
#include <mi.h>
#include <proc.h>
#include <bseerr.h>
#include <sigdef.h>
#include <except.h>
#include <dossymc.h>
#include <seldesc.h>
#include <pgexport.h>
#include <vmexport.h>
#include <vmowner.h>
#include <tkexport.h>
#include <sem.h>
#include <screen.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <selxport.h>
#include <semxport.h>
#include <tkptda.h>
#include <bsetib.h>
#include <tklocal.h>
#include <kmode.h>
#include <sigxport.h>
#include <bsexcpt.h>
#include <exmg.h>

/* Global context hook for interrupt time signal handling */
PHOOK pSigGCH;

/***EP  SIGInitContextHook - Allocate signal context hook
 *
 *      Allocate the global context hook used to delay posting of
 *      interrupt time signals until task time.
 *
 *      EXIT    NO_ERROR
 */
ULONG SIGInitContextHook()
{
   return (KMAllocHook((PFN)SIGPostPendingHook, 0, 0, 0, KM_GLOBAL_CONTEXT,
           &pSigGCH));
}

/***EP  SIGGetMustComplete - Retrieves must complete count.
 *
 *      SIGGetMustComplete returns the current mustcomplete count
 *      from the TIB corresponding to the TCB passed in.
 *
 *      ENTRY   pTCB       - Linear address of TCB
 *              pusMCCount - Place to store MCCount
 *
 *      EXIT    None
 *
 *      PSUEDO CODE
 *
 *      Create alias to TIB
 *      Lock the alias
 *      copy usMCCount
 *      free alias to TIB
 */

void SIGGetMustComplete(PTCB pTCB, PUSHORT pusMCCount)
{
   VMAC vmac;                           /* VM access structure */
   register ULONG ulTib;                /* Address of TIB */

   ulTib = (ULONG)pTCB->TCBptib;

   *pusMCCount = 0;

   if (VMMapAlias(VMAC_ARENASYS|PG_R|VMAC_LOCANY, /* system arena,readable */
              0,                               /* no SELAlloc flags */
              0,                               /* no alias flags */
              0,                               /* don't map specific alias */
              0,                               /* valid in current context */
              ulTib & ~PAGEMASK,               /* TIB */
              pTCB->TCBpPTDA->ptda_handle,     /* Handle to correct context */
              ((((ulTib & PAGEMASK) + sizeof(struct tibp_s) & ~PAGEMASK) > 0) ?
              2 * PAGESIZE : PAGESIZE),        /* Min alias size */
              SSToDS(&vmac)) != NO_ERROR)      /* return info buffer */
      return;                                  /* Can't check */

   TKFuWordNF(pusMCCount, &(((PTIBP)(vmac.ac_va + (ulTib & PAGEMASK)))
                                      ->tibp_depend.tib2_usMCCount));

   VMFreeMem(vmac.ac_va,0,0);   /* free the alias */
   return;
}

/***EP  SIGSetMustCompleteFlag - Turns on the fMCForceFlag
 *
 *      SIGSetMustCompleteFlag sets the must complete force flag
 *      in the TIB corresponding to the TCB passed in.
 *
 *      ENTRY   pTCB       - Linear address of TCB
 *
 *      EXIT    Success - NO_ERROR
 *
 *      PSUEDO CODE
 *
 *      Create alias to TIB
 *      Lock the alias
 *      set the force flag
 *      free alias to TIB
 */

ULONG SIGSetMustCompleteFlag(PTCB pTCB)
{
   VMAC vmac;                           /* VM access structure */
   register ULONG ulTib;                /* Address of TIB */

   ulTib = (ULONG)pTCB->TCBptib;

   if (VMMapAlias(VMAC_ARENASYS|PG_R|PG_W|VMAC_LOCANY, /* system arena,R/W*/
              0,                               /* no SELAlloc flags */
              0,                               /* no alias flags */
              0,                               /* don't map specific alias */
              0,                               /* valid in current context */
              ulTib & ~PAGEMASK,               /* TIB */
              pTCB->TCBpPTDA->ptda_handle,     /* Handle to correct context */
              ((((ulTib & PAGEMASK) + sizeof(struct tibp_s) & ~PAGEMASK) > 0) ?
              2 * PAGESIZE : PAGESIZE),        /* Min alias size */
              SSToDS(&vmac)) != NO_ERROR)      /* return info buffer */
      return (FALSE);                          /* Can't check, assume NO */

   TKSuWordNF(1,&((PTIBP)(vmac.ac_va + (ulTib & PAGEMASK)))
      ->tibp_depend.tib2_fMCForceFlag);

   VMFreeMem(vmac.ac_va,0,0);   /* free the alias */
   return NO_ERROR;
}

/***LP  TKApiSetSignalExceptionFocus - request signal focus
 *
 *      Worker for VR32SetSignalExceptionFocus. Allows a 32-bit app to
 *      specify that 32-bit exception handlers should be passed signals.
 *
 *      ENTRY   fOperation - Set/Reset Focus
 *              pulNesting - ptr to spot to store nesting level
 *
 *      EXIT    Success    - NO_ERROR
 *              Failure    - ERROR_NESTING_TOO_DEEP
 *                           ERROR_ALREADY_RESET
*/

ULONG TKApiSetSignalExceptionFocus(ULONG fOperation,    /* Set or Reset */
                                   PULONG pulNesting) { /* To store Nesting */

   // don't let pm app's steal focus from the shell
   if (pPTDACur->ptda_ProcType == PT_PRESMGR)
       return(ERROR_INVALID_PROCID);


   if (fOperation == SIG_SETFOCUS) {
      if (pPTDACur->SigFocusCnt == SIG_MAXSF)
         return(ERROR_NESTING_TOO_DEEP);

      pPTDACur->SigFocusCnt++;
      if ((pPTDACur->ptda_ProcType != PT_DETACHED) &&
          (pPTDACur->ptda_ProcType != PT_VIOWIN)) {
         SigFocus[pPTDACur->ptda_infoseg.LIS_CurScrnGrp].sfi_sigintr =
             pPTDACur->ptda_Pid;
         SigFocus[pPTDACur->ptda_infoseg.LIS_CurScrnGrp].sfi_sigbreak =
             pPTDACur->ptda_Pid;
      }
      pPTDACur->Sig_hndf |= (SIGNumToMask(SIGINTR) | SIGNumToMask(SIGBREAK));
   } else if (fOperation == SIG_RESETFOCUS) {
      if (pPTDACur->SigFocusCnt == 0)
         return (ERROR_ALREADY_RESET);

      if (--pPTDACur->SigFocusCnt == 0) {
         if (pPTDACur->Sig_vec[SIGINTR-1] == NULL) {
            SigResetSigFocus(SIGINTR);
            pPTDACur->Sig_hndf &= ~SIGNumToMask(SIGINTR);
         }
         if (pPTDACur->Sig_vec[SIGBREAK-1] == NULL) {
            SigResetSigFocus(SIGBREAK);
            pPTDACur->Sig_hndf &= ~SIGNumToMask(SIGBREAK);
         }
      }
   } else
      return (ERROR_INVALID_FUNCTION);

   /* Clear out all references to SIGINTR and SIGBREAK in the
    * Sig_* flags, and reset the bit in Sig_hndf if we've become
    * signals aware. Note that since the SIGNumToMask() calls are a
    * macro the right hand side compiles down to a number and repeating
    * the calculation is thus faster than storing the result somewhere.
    */

   pPTDACur->Sig_errf &= ~(SIGNumToMask(SIGINTR) | SIGNumToMask(SIGBREAK));
   pPTDACur->Sig_ignf &= ~(SIGNumToMask(SIGINTR) | SIGNumToMask(SIGBREAK));

   if (pPTDACur->ptda_pTCBHead->TCBSig_pend &
       ~(pPTDACur->ptda_pTCBHead->TCBSig_cur))   // dispatchable signals ?
      pPTDACur->ptda_pTCBHead->TCBForcedActions |= TK_FF_SIG;

   *pulNesting = pPTDACur->SigFocusCnt;
   return(NO_ERROR);
}

/***EP  VR32SetSignalExceptionFocus - request signal focus
 *
 *      Allows a 32-bit app to specify that 32-bit exception handlers
 *      should be passed signals.
 *
 *      ENTRY   fOperation - Set/Reset Focus
 *              pulNesting - ptr to spot to store nesting level
 *
 *      EXIT    Success    - NO_ERROR
 *              Failure    - ERROR_NESTING_TOO_DEEP
 *                           ERROR_ALREADY_RESET
*/

ULONG cdecl VR32SetSignalExceptionFocus(THUNKSEF sef,       /* System Entry Frame */
                                        ULONG fOperation,   /* Set/Reset */
                                        PULONG pulNesting)  /* Nesting */
{
   ULONG rc;
   ULONG ulNesting;

   if (pulNesting >= (PULONG) SEL_512MEG) {
      TKUsrMemPageFault((ULONG)pulNesting);
      return (ERROR_INVALID_PARAMETER);
   }

   if ((rc = TKApiSetSignalExceptionFocus(fOperation, SSToDS(&ulNesting)))
       != NO_ERROR)
      return (rc);

   TKSuDWord(ulNesting,pulNesting);
   return (NO_ERROR);
}



/***EP  VR32SendSignalException - Send an asyncronous exception
 *
 *      VR32SendSignalException sends an asyncronous exception to
 *      the process tree starting at pid. It's basically a thunk
 *      to DosSendSignal
 *
 *      ENTRY   ulExceptNum - Exception number
 *              pid         - Process ID
 *
 *      EXIT    Success    - NO_ERROR
 *              Failure    - ERROR_NO_SIGNAL_SENT
 *                           ERROR_NOT_DESCENDANT
 *                           ERROR_SIGNAL_REFUSED
 *                           ERROR_INVALID_FUNCTION
 *                           ERROR_INVALID_PROCID
*/

ULONG cdecl VR32SendSignalException(THUNKSEF sef,/* System Entry Frame */
                              PID pid,           /* PID of process tree */
                              ULONG ulExceptNum) /* Exception number */
{
   switch (ulExceptNum) {
   case XCPT_SIGNAL_INTR:
   case XCPT_SIGNAL_BREAK:
      return (SIGApiSendSignalException(pid, ulExceptNum));
      break;

   default:
      return(ERROR_INVALID_SIGNAL_NUMBER);
   }

}

/***EP  VR32AcknowledgeSignalException - Acknowledge a signal exception.
 *
 *      VR32AcknowledgeSignalException acknowledges a signal from
 *      flat code. It is essentially a thunk to the SIG_ACK function
 *      of Dos16SetSignal.
 *
 *      ENTRY   ulSignalNum - Signal number
 *
 *      EXIT    Success  - NO_ERROR
 *              Failure  - ERROR_INVALID_SIGNAL_NUMBER
 *
 */

ULONG cdecl VR32AcknowledgeSignalException(THUNKSEF sef,      /* System Entry Frame */
                                               ULONG ulSignalNum) /* Sig number */
{
   switch (ulSignalNum) {
   case XCPT_SIGNAL_INTR:
   case XCPT_SIGNAL_KILLPROC:
   case XCPT_SIGNAL_BREAK:
#ifdef SECURITY                                                     //@SEC
      /*                                                                   @SEC
       * If a KILLPROC signal exception is acknowledged while a forced     @SEC
       * kill process is in progress, we will not call the                 @SEC
       * 16 bit signal handlers to inform them of the kill process.        @SEC
       * The following code prevents the above from happening.             @SEC
       */                                                                //@SEC
      if ((ulSignalNum == XCPT_SIGNAL_KILLPROC) &&                       //@SEC
         (pPTDACur->SigFTerm == (USHORT)-1))                             //@SEC
            return(NO_ERROR);                                            //@SEC
#endif                                                                   //@SEC
      SigReset(ulSignalNum, XCPT_CONTINUE_EXECUTION);
      return(NO_ERROR);
      break;

   case XCPT_SIGNAL_APTERM:                                        /*108449*/
      SigResetAPTERM(ulSignalNum, XCPT_CONTINUE_EXECUTION);        /*108449*/
      return(NO_ERROR);                                            /*108449*/
      break;                                                       /*108449*/

   default:
      return(ERROR_INVALID_SIGNAL_NUMBER);
   }

}
