/****************************************************************************/
/*                                                                          */
/*                    Copyright (c) IBM Corporation 1992, 1993              */
/*                           All Rights Reserved                            */
/*                                                                          */
/* SOURCE FILE NAME: SHINIT.C                                               */
/*                                                                          */
/* DESCRIPTIVE NAME:  Stream Handler Dll Initialization routine             */
/*                                                                          */
/* FUNCTION: This function is called each time a new process loads this     */
/*           DLL.  If this is the first call, we must register with the     */
/*           SSM as a handler.  For each call, we need to allocate any      */
/*           resources needed on a process basis (GetSeg's, etc), and       */
/*           set up an exit list routine to deallocate these resources.     */
/*                                                                          */
/* ENTRY POINTS:                                                            */
/*   _DLL_InitTerm                                                          */
/*   ShExitList                                                             */
/*************************** END OF SPECIFICATIONS **************************/

#ifdef MMRAS
#define MMRAS_PTRACE
#endif
#ifdef PTRACE
#define MMRAS_PTRACE
#endif

#define  INCL_NOPMAPI                  /* no PM include files required */
#define  INCL_DOSSEMAPHORES
#define  INCL_DOSPROCESS               /* For exit list defines        */
#define  INCL_DOSERRORS
#define  INCL_DOSMISC
#define  INCL_DOSDEVICES
#include <os2.h>
#include <os2me.h>
#include <hhpheap.h>
#include <shi.h>
#include <fssh.h>

#ifdef MMRAS_PTRACE
#include <ptrace.h>
#endif

int            _CRT_init(void);

#ifdef MMDEBUGPRINT
void myprint(char *s);
void myprint1(char *s, long rc);
#endif
/************************** START OF SPECIFICATIONS *************************/
/*                                                                          */
/* SUBROUTINE NAME: ShInit                                                  */
/*                                                                          */
/* DESCRIPTIVE NAME: Stream Handler Initialization routine                  */
/*                                                                          */
/* FUNCTION: DLL initialization routine, to set up control blocks, allocate */
/*           storage etc.                                                   */
/*                                                                          */
/* NOTES:                                                                   */
/*                                                                          */
/* ENTRY POINT: _DLL_InitTerm                                               */
/*   LINKAGE:   CALL NEAR (0:32)                                            */
/*                                                                          */
/* INPUT:                                                                   */
/*   HMODULE hmod        Module handle                                      */
/*   ULONG   fTerm       DLL termination flag                               */
/*                                                                          */
/* EXIT-NORMAL: NO_ERROR (0)                                                */
/*                                                                          */
/* EXIT-ERROR:                                                              */
/*   ERROR_ALLOC_RESOURCES                                                  */
/*                                                                          */
/* SIDE EFFECTS:                                                            */
/*                                                                          */
/* INTERNAL REFERENCES:                                                     */
/*        ROUTINES: None                                                    */
/*                                                                          */
/* EXTERNAL REFERENCES:                                                     */
/*   ROUTINES:                                                              */
/*     _CRT_init                                                            */
/*     DosCreateMutexSem                                                    */
/*     DosOpenMutexSem                                                      */
/*     DosRequestMutexSem                                                   */
/*     DosCloseMutexSem                                                     */
/*     SMHEntryPoint                                                        */
/*     HhpCreateHeap                                                        */
/*     HhpAccessHeap                                                        */
/*     DosExitList                                                          */
/*     HhpReleaseHeap                                                       */
/*     DosReleaseMutexSem                                                   */
/*                                                                          */
/*   DATA STRUCTURES:                                                       */
/*     hmtxGlobalData                                                       */
/*     hHeap                                                                */
/*                                                                          */
/*************************** END OF SPECIFICATIONS **************************/

#ifdef MMDEBUGPRINT
void APIENTRY fsshDummy()
{
  myprint("Inside fsshDummy\n");
  //  _FSSHInitTerm(0, 0);
}
#endif

//ULONG _DLL_InitTerm( HMODULE hmod, ULONG fTerm)
ULONG APIENTRY _FSSHInitTerm( HMODULE hmod, ULONG fTerm);
ULONG APIENTRY _FSSHInitTerm( HMODULE hmod, ULONG fTerm)

{ /* Start of ShInit */

RC rc = NO_ERROR;                       /* local return code */
PARM_REG smhRegParm;                    /* Parameters for SMH_REGISTER */
int Registered = FALSE;
int HeapAllocated_Attached = FALSE;
int GlobDataMtxCreated = FALSE;
int  _CRT_init(void);
void _CRT_term(void);
hmod;

#ifdef MMDEBUGPRINT
  // Vivek's hacks
  myprint("enter fssh_initterm\n");
#endif
  /*
   * Checking this parameter will insure that this routine will only
   * be run on an actual initialization.  Return success from the
   * termination.
   */

  if (fTerm)
     {
#ifdef _V3_CRT_
     _CRT_term();   /* Clean up runtime environment */
#endif
     return (1L);
     }

  if (_CRT_init())
     {
     return (0L);
     }

  /*
   * Get the semaphore controlling the process count & update the process
   * count if successful.  Then after we have the sem, if the count is
   * one, we are guaranteed that we must do the global initializations.
   *
   * There is a problem that to determine if we need to create or open the
   * semaphore we need to check the ProcessCount to see if this is the
   * first process, but since we don't have the semaphore we don't have
   * a guarentee the count won't change.  If we get caught in this window
   * then we will fail to get the semaphore and the rc will indicate error.
   */
  rc = DosCreateMutexSem(pszProcCntMutexName, &hmtxProcCnt, 0L, FALSE);
  if (rc == ERROR_DUPLICATE_NAME)
    rc = DosOpenMutexSem(pszProcCntMutexName, &hmtxProcCnt);
  if (rc)
    return(0);

  rc = DosRequestMutexSem(hmtxProcCnt, SEM_INDEFINITE_WAIT);
  if (rc)
     DosCloseMutexSem(hmtxProcCnt);

  if (!ulProcessCount)
  {
    pESPCB_ListHead = NULL;                  /* Pointer to list of Extended SPCB's */
    pSIB_list_head = NULL;                   /* Pointer to list of SIB's in use */
    pszHandlerName = (PSZ)FSSH_HANDLER_NAME; /* Name of this stream handler */
    ulHandlerVersion = FSSH_VERSION;         /* Version of this handler */
    SrcHandlerID = 0;                        /* Handler ID returned from Register */
    TgtHandlerID = 0;                        /* Handler ID returned from Register */
    hHeap = NULL;                            /* Handle of heap for SIB's and EVCB's */
    hmtxGlobalData = 0;                      /* Handle of semaphore to control the */
//  ShWriteRtn = (PFNTHREAD) FsshWrite;      /* Write routine */
//  ShReadRtn = (PFNTHREAD) FsshRead;        /* Read routine */
//  pfnShInstallCheck = NULL;  /* variable to hold @ of install check routine */
//  pfnShcSendMsg = NULL;      /* variable to hold @ of ShcSendMsg routine */
//  pfnShcGetTime = NULL;      /* variable to hold @ of ShcGetTime routine */
//  pfnShcEnableEvent = NULL;  /* variable to hold @ of ShcEnableEvent routine */
//  pfnShcDisableEvent = NULL; /* variable to hold @ of ShcDisableEvent routine */
//  pfnShcEnableSync = NULL;   /* variable to hold @ of ShcEnableSync routine */
//  pfnShcDisableSync = NULL;  /* variable to hold @ of ShcDisableSync routine */
    ulHandlerFlags = HANDLER_CAN_BE_SOURCE | HANDLER_CAN_BE_TARGET ;
  } /* first process */

  if (!rc)
  { /* Semaphore ok, In critical section */
    /*
     * If this is the first time this init routine is called then we are
     * being brought in by the loader the first time, so we need to register
     * with the SSM.
     */
    ulProcessCount++;
    if (ulProcessCount == 1)
      { /* First process */
        smhRegParm.ulFunction = SMH_REGISTER;
        smhRegParm.pszSHName = pszHandlerName;
        smhRegParm.phidSrc = &SrcHandlerID;
        smhRegParm.phidTgt = &TgtHandlerID;
        smhRegParm.pshcfnEntry = ( PSHCFN ) ShcRouter;

        smhRegParm.ulFlags = 0L;
        if (ulHandlerFlags & HANDLER_CAN_BE_SOURCE)
          {
            smhRegParm.ulFlags = REGISTER_SRC_HNDLR;
          }
        if (ulHandlerFlags & HANDLER_CAN_BE_TARGET)
          {
            smhRegParm.ulFlags |= REGISTER_TGT_HNDLR;
          }
        if (ulHandlerFlags & HANDLER_IS_NONSTREAMING)
          {
            smhRegParm.ulFlags |= REGISTER_NONSTREAMING;
          }

        rc = SMHEntryPoint((PVOID)&smhRegParm);
        /*
         * If ok then allocate our memory pool (heap), since it is under
         * semaphore control create and get the semaphore first.
         */
        if (!rc)
          { /* Register ok */
            Registered = TRUE;
            hHeap = HhpCreateHeap(HEAPSIZE,
                                  HH_SHARED);
            if (hHeap)
              { /* Heap Allocated */
                HeapAllocated_Attached = TRUE;
                if (!(rc = DosCreateMutexSem(NULL,
                                             &hmtxGlobalData,
                                             DC_SEM_SHARED,
                                             FALSE)))
                  {
                    GlobDataMtxCreated = TRUE;
                  }
              } /* Heap Allocated */
            else
              { /* Heap not allocated */
                rc = ERROR_ALLOC_RESOURCES;
              } /* Heap not allocated */
          } /* Register ok */
      } /* First Process */
    else
      { /* Not first process */
        if (!(rc = DosOpenMutexSem(NULL,
                                   &hmtxGlobalData)))
          { /* Global data semaphore opened */

            GlobDataMtxCreated = TRUE;

            if (!ENTERCRIT(rc))
              { /* Global Data Sem obtained */

                if (HhpAccessHeap(hHeap, HhpGetPID()))
                  { /* Error accessing heap */
                    rc = ERROR_ALLOC_RESOURCES;
                  } /* Error accessing heap */
                else
                  { /* Heap attached */
                    HeapAllocated_Attached = TRUE;
                  } /* Heap attached */

                EXITCRIT;

              } /* Global Data Sem obtained */
          } /* Global data semaphore opened */
      } /* Not first process */

    /*
     * If things are ok, Register an exit list handler and if that works
     * increment the process count.
     */
    if (!rc)
      {
        rc = DosExitList(EXTLSTADD_ORDER,
                         (PFNEXITLIST)ShExitList);
      }

    if (rc)
      { /* Error occurred - Clean Up */
        if (HeapAllocated_Attached)
          {
            HhpReleaseHeap(hHeap,
                           HhpGetPID());
          }
        if (GlobDataMtxCreated)
          {
            DosCloseMutexSem(hmtxGlobalData);
          }
        if (Registered)
          { /* Deregister */
            PARM_DEREG smhDeregParm;

            smhDeregParm.ulFunction = SMH_DEREGISTER;
            smhDeregParm.pszSHName = pszHandlerName;
            SMHEntryPoint(&smhDeregParm);
          } /* Deregister */
        ulProcessCount--;
        DosReleaseMutexSem(hmtxProcCnt);
        DosCloseMutexSem(hmtxProcCnt);
      } /* Error occurred - Clean Up */
    else
      {
#ifdef MMRAS_PTRACE
        InitPTrace()
#endif
        DosReleaseMutexSem(hmtxProcCnt);
      }

  } /* Semaphore ok, In critical section */
  /*
   * The return codes expected are:
   *  TRUE (any non-zero) - init routine worked
   *  FALSE (zero)        - init routine failed
   *
   * So we have to reverse the local rc before we pass it back.
   */
  return(!rc);

} /* End of SHInit */

/************************** START OF SPECIFICATIONS *************************/
/*                                                                          */
/* SUBROUTINE NAME: ShExitList                                              */
/*                                                                          */
/* DESCRIPTIVE NAME: Stream Hanlder Exit List routine                       */
/*                                                                          */
/* FUNCTION: Clean up resources allocated for each process, and if this is  */
/*           the last process, then deregister with the SSM.                */
/*           In all cases we need to destroy all streams owned by this      */
/*           process.                                                       */
/*                                                                          */
/* ENTRY POINT:                                                             */
/*   LINKAGE:   CALL NEAR (0:32)                                            */
/*                                                                          */
/* INPUT:                                                                   */
/*                                                                          */
/* EXIT-NORMAL: NO_ERROR (0)                                                */
/*                                                                          */
/* EXIT-ERROR:                                                              */
/*   None                                                                   */
/*                                                                          */
/* SIDE EFFECTS:                                                            */
/*                                                                          */
/* INTERNAL REFERENCES:                                                     */
/*        ROUTINES: None                                                    */
/*                                                                          */
/* EXTERNAL REFERENCES:                                                     */
/*   ROUTINES:                                                              */
/*     HhpGetPID                                                            */
/*     DosRequestMutexSem                                                   */
/*     DosCloseMutexSem                                                     */
/*     SMHEntryPoint                                                        */
/*     HhpShcDestroy                                                        */
/*     DosExitList                                                          */
/*     HhpReleaseHeap                                                       */
/*     DosReleaseMutexSem                                                   */
/*                                                                          */
/*   DATA STRUCTURES:                                                       */
/*     hmtxGlobalData                                                       */
/*     hHeap                                                                */
/*                                                                          */
/*************************** END OF SPECIFICATIONS **************************/

VOID APIENTRY ShExitList()

{ /* Start of ShExitList */

PSIB psib;                              /* Stream instance block */
PSIB psibToDestroy = NULL;              /* Stream instance block to destroy */
PARM_DESTROY dyparm;                    /* parameter block to destroy routine */
PID  pid;                               /* Process ID */
RC   rc;                                /* Return code */

  /*
   * There is nothing we can do if calls fail, so don't bother checking.
   */

  DosRequestMutexSem(hmtxProcCnt, SEM_INDEFINITE_WAIT);

  /*
   * If this is the last process we will be removed from memory, so
   * call SSM to deregister.
   */

  if (ulProcessCount == 1)
    {
      PARM_DEREG smhDeregParm;

      smhDeregParm.ulFunction = SMH_DEREGISTER;
      smhDeregParm.pszSHName = pszHandlerName;
      SMHEntryPoint(&smhDeregParm);
    }

  /* We need to call destroy for each stream created by this process. */
  /*   Get the PID, and the global data semaphore. */
  /*   Search the SIB chain for this process's stream instances. */
  /*   Call destroy to destroy the stream instances */
  /*   Release the global data semaphore */

  pid = HhpGetPID();

  ENTERCRIT(rc);
  psib = pSIB_list_head;
  while (psib)
    {
      if (psib->ProcessID == pid)
        {
          psibToDestroy = psib;
          psib = psib->pnxtSIB;
          if (psibToDestroy->ThreadID)
            {
              psibToDestroy->ulActionFlags |= SIBACTFLG_THREAD_DEAD;
            }
          dyparm.hstream = psibToDestroy->hStream;
          dyparm.hid = psibToDestroy->HandlerID;
          ShcDestroy(&dyparm);
        }
      else
        {
          psib = psib->pnxtSIB;
        }
    }

  /*
   * Unattach from the memory pool, and from the Global data semaphore
   */
  HhpReleaseHeap(hHeap, pid);
  EXITCRIT;
  DosCloseMutexSem(hmtxGlobalData);

  /* Clean up the process count variable and it's semaphore. */

  ulProcessCount--;
  DosReleaseMutexSem(hmtxProcCnt);
  DosCloseMutexSem(hmtxProcCnt);

  DosExitList(EXLST_EXIT, (PFNEXITLIST)ShExitList);

} /* End of ShExitList */
