/*static char *SCCSID = "@(#)dispatch.c	6.4 91/10/22";*/
/*      SCCSID = @(#)dispatch.c	6.4 91/10/22 */

/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*************************** START OF SPECIFICATION *****************
 *
 * Source File Name: dispatch.c
 *
 * Descriptive Name: Ring 3 Thread Exception Dispatcher
 *
 * Status: OS/2 Release 2.00
 *
 * Function: This file contains the ring 3 thread exception dispatcher
 *      which is called, actually returned to, by ring 0 code.
 *
 * Notes: This routine is returned to from the trap manager,
 *      signal manager, and memory manager.  It is NEVER called directly.
 *
 * Entry Points:
 *      Dos32R3ExceptionDispatcher
 *
 * External References:
 *    Routines:
 *      Dos32UnwindException        - Unwind handlers for process
 *      Dos32ExceptionCallBack      - callback kernel to continue
 *                                    exception processing
 *
 *    Data Structures:
 *      XCPT                        - exception fault context
 *
 *************************** END OF SPECIFICATION *******************/
#define INCL_ERRORS
#define INCL_DOSPROCESS
#define INCL_DOSEXCEPTIONS
#define INCL_NOPMAPI

/*
 * The following defines create the correct names for Dos* while still
 * allowing use of definitions from os2.h
 */

#define DosUnwindException DOS32UNWINDEXCEPTION

#include <os2.h>

// #include <string.h>
#include <r3except.h>

/*************************** START OF SPECIFICATION *****************
 *
 * Function Name: Dos32R3ExceptionDispatcher
 *
 * Descriptive Name: Ring 3 Thread Exception Dispatcher
 *
 * Function: Call thread exception handlers until one handles the
 *      exception or none are left. Then call back to the kernel to
 *      finish processing the exception.
 *
 *  Notes: This routine is never called directly.  It is jumped into
 *      by fiddling with the ring 3 stack at ring 0 and doing a
 *      (far) return from ring 0.
 *
 *         Return with ExceptionNum in structure pXcpt and EC_cr2 in
 *      structure pXcpt->pExceptionContext equal to what they were on
 *      entry. Unless it is a guard page exception, in which case we
 *      change ExceptionNum to XCPT_GPAF (guard page allocation failure).
 *      In fact one should NEVER return to the kernel with ExceptionNum
 *      set to XCPT_GPF (the kernel will panic).
 *
 * Entry Point: Dos32R3ExceptionDispatcher
 *    Linkage: call 32 near
 *
 * Input:
 *      ulTrapNumber      = Trap number
 *      pERepRec          = pointer to exception report record
 *      pContext          = pointer to exception context record
 *
 * Exit Normal: None
 *
 * Exit Error: None
 *
 * Side Effects: This routine does not return normally (via a return
 *      statement).  Dos32ExceptionCallBack will clean up the stack
 *      and return for this routine.
 *
 * External References:
 *    Routines:
 *      Dos32UnwindException        - Unwind handlers for process
 *      Dos32ExceptionCallBack      - callback kernel to continue
 *                                    exception processing
 *    Data Structures:
 *      XCPT                        - Exception structure
 *
 *************************** END OF SPECIFICATION *******************/

void APIENTRY DOS32R3EXCEPTIONDISPATCHER( ULONG ulTrapNumber,
                                          PEXCEPTIONREPORTRECORD pERepRec,
                                          PCONTEXTRECORD pContext)
{
   ULONG   rc;                  /* return code from user handler */
   ULONG   IsAsync;
   EXCEPTIONREPORTRECORD ERepRec2;
   EXCEPTIONREPORTRECORD ERepRec3;
   CONTEXTRECORD Context2;

   /*
    * Call handler(s) until one handles it or end of chain is reached.
    * Asynchronous exceptions have a read-only context since it does
    * not make any sense to modify a non-faulting context.  This also
    * hinders the ability exception handlers have to view and modify
    * system internals, since the exception could have occurred while
    * we were within a system call.
    */
   IsAsync = (pERepRec->ExceptionNum == XCPT_ASYNC_PROCESS_TERMINATE ||
              pERepRec->ExceptionNum == XCPT_SIGNAL);

   if (IsAsync) {
       memcpy(&Context2, pContext, sizeof(CONTEXTRECORD));
   }

   rc = xcptR3ExceptionDispatcher(pERepRec, pContext);

   if (IsAsync) {
       memcpy(pContext, &Context2, sizeof(CONTEXTRECORD));
   }

   if (rc == XCPT_CONTINUE_SEARCH) {
      /*
      * If guard page fault was not handled, do system default action,
      * which is to remark the guard page as useable and try to allocate
      * the next page as a guard page.
      */
      if (pERepRec->ExceptionNum == XCPT_GUARD_PAGE_VIOLATION) {

         if (xcptGPFDefaultAction((PVOID)pERepRec->ExceptionInfo[1]) != NO_ERROR) {

            /*
            * We were unable to grow the stack segment, so raise a
            * XCPT_UNABLE_TO_GROW_STACK exception.
            */

            memcpy(&Context2, pContext, sizeof(CONTEXTRECORD));
            ERepRec2.ExceptionNum = XCPT_UNABLE_TO_GROW_STACK;
            ERepRec2.fHandlerFlags = EH_NESTED_CALL;
            ERepRec2.NestedExceptionReportRecord = pERepRec;
            ERepRec2.ExceptionAddress = pERepRec->ExceptionAddress;
            ERepRec2.cParameters = 0;
            rc = xcptR3ExceptionDispatcher(&ERepRec2, &Context2);
         }
      }


      if ((pERepRec->ExceptionNum == XCPT_PROCESS_TERMINATE) ||
          (pERepRec->ExceptionNum == XCPT_ASYNC_PROCESS_TERMINATE)) {
         ERepRec3.ExceptionNum = XCPT_UNWIND;
         ERepRec3.fHandlerFlags = EH_NESTED_CALL | EH_EXIT_UNWIND | EH_UNWINDING;
         ERepRec3.NestedExceptionReportRecord = pERepRec;
         ERepRec3.ExceptionAddress = pERepRec->ExceptionAddress;
         ERepRec3.cParameters = 0;

         DosUnwindException(0, 0, &ERepRec3);
      }
   }
   /*
    * Call back to the kernel and let it decide what to do from here.
    */
   DOS32EXCEPTIONCALLBACK(ulTrapNumber, pERepRec, pContext, rc);

   /* should never get here */
}

