/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
// handler.c

#define INCL_DEV
#define INCL_DOS
#define INCL_GPI
#define INCL_SPL
#include <os2.h>


#define INCL_32
#define INCL_VMANDDI
#include <ddi.h>

#define INCL_GREALL
#define INCL_GRE_DEVICESURFACE
#include <pmddi.h>


// this from \drf6\h\bsedos.h
APIRET APIENTRY DosQueryModFromEIP(HMODULE *phMod, ULONG *pObjNum, ULONG BuffLen, PCHAR pBuff, ULONG *pOffset, ULONG Address);

// c includes
#include <setjmp.h>


#define INCL_GENPLIB_JOURNAL
#define INCL_GENPLIB_MEMORY
#include <genplib.h>



#include "def.h"
#include "driver.h"
#include "funcs.h"


// --------------------------------------------------------------------------------------------------------------------
// exception handler function; jump back into function that had a problem

ULONG APIENTRY Handler( PEXCEPTIONREPORTRECORD p1, PEXCEPTIONREGISTRATIONRECORD p2, PCONTEXTRECORD p3, PVOID pv )
{
  APIRET    rc;
  HMODULE   hmod;
  ULONG     ulObjNum;
  ULONG     ulOffset;
  char      achBuffer[ 10 ];
  BOOL      fHandle = FALSE;

  // handle interesting exceptions
  switch( p1->ExceptionNum ) {
  case XCPT_ACCESS_VIOLATION:
  case XCPT_INTEGER_DIVIDE_BY_ZERO:
  case XCPT_INTEGER_OVERFLOW:
    // handle if it occurred in driver code
    assert( p3 );
    if( CONTEXT_CONTROL & p3->ContextFlags ) {
      rc = DosQueryModFromEIP( &hmod, &ulObjNum, sizeof( achBuffer ), achBuffer, &ulOffset, p3->ctx_RegEip );
      assert( rc == 0 );
      fHandle |= ( hmod == globals.hModule );
    } else {
      fHandle |= TRUE;
    }
    break;
  case XCPT_PROCESS_TERMINATE:
  case XCPT_ASYNC_PROCESS_TERMINATE:
    // handle thread exits
    fHandle |= TRUE;
    break;

  case XCPT_USER:
    // handle user-raised ones always
    fHandle |= TRUE;
    break;

  case XCPT_BREAKPOINT:
    return XCPT_CONTINUE_EXECUTION;
  }

  if( fHandle ) {
    // return exception number to setjmp()
    longjmp( ((PREGREC)p2)->jmp,  p1->ExceptionNum );
  }

  // not interested; system should continue search
  return XCPT_CONTINUE_SEARCH;
}




// --------------------------------------------------------------------------------------------------------------------
// Called when thread owning the DC is getting killed.
// Free up the DC so that some other thread in the process can continue to use it

LONG DRVENTRY CheckForTermination( PREGREC pregrec, ULONG ulException, PDDC pddc  )
{
  ULONG   ulcRequests;
  APIRET  rc;
  TID     tid;
  PID     pid;
  PTIB    ptib;
  PPIB    ppib;


  switch( ulException ) {
  case XCPT_PROCESS_TERMINATE:
  case XCPT_ASYNC_PROCESS_TERMINATE:
    // get current thread id
    rc = DosGetInfoBlocks( &ptib, &ppib );
    assert( 0 == rc );
    // get DDC semaphore data
    rc = DosQueryMutexSem( pddc->hmtxDCSem, &pid, &tid, &ulcRequests );
    assert( 0 == rc );
    // see if current, dying thread owns the semaphore
    if( ulcRequests  && tid == ptib->tib_ptib2->tib2_ultid ) {
      // whoa! the thread that owns this ddc just got killed
      while( ulcRequests-- ) {
        rc = DosReleaseMutexSem( pddc->hmtxDCSem );
        assert( 0 == rc );
      }
    }
    // get the handler off the chain, or else it would just get called again
    rc = DosUnsetExceptionHandler( (PEXCEPTIONREGISTRATIONRECORD)pregrec );
    assert( 0 == rc );

    // exit the thread; let other handlers have a go at it
    DosExit( EXIT_THREAD, 0 );
  }
  return 0;
}
