#pragma strings( readonly )
/******************************************************************************/
/*                                                                            */
/* SAMPLE05.C                                                                 */
/*                                                                            */
/* COPYRIGHT:                                                                 */
/* ----------                                                                 */
/* Copyright (C) International Business Machines Corp., 1991, 1993.           */
/*                                                                            */
/* DISCLAIMER OF WARRANTIES:                                                  */
/* -------------------------                                                  */
/* The following [enclosed] code is sample code created by IBM                */
/* Corporation.  This sample code is not part of any standard IBM product     */
/* and is provided to you solely for the purpose of assisting you in the      */
/* development of your applications.  The code is provided "AS IS",           */
/* without warranty of any kind.  IBM shall not be liable for any damages     */
/* arising out of your use of the sample code, even if they have been         */
/* advised of the possibility of such damages.                                */
/*                                                                            */
/* This example provides 5 external entrypoints of which 2 are exported for   */
/* use by client processes.  The entrypoints are:                             */
/*                                                                            */
/* _DLL_InitTerm - Initialization/Termination function for the DLL that is    */
/*                 invoked by the loader.  When the /Ge- compile option is    */
/*                 used the linker is told that this is the function to       */
/*                 execute when the DLL is first loaded and last freed for    */
/*                 each process.                                              */
/*                                                                            */
/* DLLREGISTER  - Called by _DLL_InitTerm for each process that loads the     */
/*                DLL.                                                        */
/*                                                                            */
/* DLLINCREMENT - Accepts a count from its client and adds this value to      */
/*                the process and system totals.                              */
/*                                                                            */
/* DLLSTATS     - Dumps process and system totals on behalf of its client.    */
/*                                                                            */
/* DLLDEREGISTER- Called by _DLL_InitTerm for each process that frees the     */
/*                DLL.                                                        */
/*                                                                            */
/******************************************************************************/

#define  INCL_DOS
#define  INCL_DOSERRORS
#define  INCL_NOPMAPI
#include <os2.h>
#include <stdio.h>
#include "sample05.h"

int _dllentry;

unsigned long _System _DLL_InitTerm( unsigned long hModule, unsigned long ulFlag );

static unsigned long DLLREGISTER( void );
static unsigned long DLLDEREGISTER( void );

#define SHARED_SEMAPHORE_NAME "\\SEM32\\SAMPLE05\\DLL.LCK"

/* The following data will be per-process data.  It will not be shared among  */
/* different processes.                                                       */

static HMTX  hmtxSharedSem;    /* Shared semaphore                            */
static ULONG ulProcessTotal;   /* Total of increments for a process           */
static PID   pidProcess;       /* Process identifier                          */

/* This is the global data segment that is shared by every process.           */

#pragma data_seg( GLOBAL_SEG )

static ULONG ulProcessCount;                /* total number of processes      */
static ULONG ulGrandTotal;                  /* Grand total of increments      */

/* _DLL_InitTerm() - called by the loader for DLL initialization/termination  */
/* This function must return a non-zero value if successful and a zero value  */
/* if unsuccessful.                                                           */

unsigned long _DLL_InitTerm( unsigned long hModule, unsigned long ulFlag )
   {
   APIRET rc;

   /* If ulFlag is zero then initialization is required:                      */
   /*    If the shared memory pointer is NULL then the DLL is being loaded    */
   /*    for the first time so acquire the named shared storage for the       */
   /*    process control structures.  A linked list of process control        */
   /*    structures will be maintained.  Each time a new process loads this   */
   /*    DLL, a new process control structure is created and it is inserted   */
   /*    at the end of the list by calling DLLREGISTER.                       */
   /*                                                                         */
   /* If ulFlag is 1 then termination is required:                            */
   /*    Call DLLDEREGISTER which will remove the process control structure   */
   /*    and free the shared memory block from its virtual address space.     */

   switch( ulFlag )
      {
   case 0:
         if ( !ulProcessCount )
            {
            _rmem_init();
            /* Create the shared mutex semaphore.                             */

            if ( ( rc = DosCreateMutexSem( SHARED_SEMAPHORE_NAME,
                                           &hmtxSharedSem,
                                           0,
                                           FALSE ) ) != NO_ERROR )
               {
               printf( "DosCreateMutexSem rc = %lu\n", rc );
               return 0;
               }
            }

         /* Register the current process.                                     */

         if ( DLLREGISTER( ) )
            return 0;

         break;

      case 1:
         /* De-register the current process.                                  */

         if ( DLLDEREGISTER( ) )
            return 0;

         _rmem_term();

         break;

      default:
         return 0;
      }

   /* Indicate success.  Non-zero means success!!!                            */

   return 1;
   }

/* DLLREGISTER - Registers the current process so that it can use this        */
/*               subsystem.  Called by _DLL_InitTerm when the DLL is first    */
/*               loaded for the current process.                              */

static unsigned long DLLREGISTER( void )
   {
   APIRET rc;
   PTIB ptib;
   PPIB ppib;

   /* Get the address of the process and thread information blocks.           */

   if ( ( rc = DosGetInfoBlocks( &ptib, &ppib ) ) != NO_ERROR )
      {
      printf( "DosGetInfoBlocks rc = %lu\n", rc );
      return rc;
      }

   /* Open the shared mutex semaphore for this process.                       */

   if ( ( rc = DosOpenMutexSem( SHARED_SEMAPHORE_NAME,
                                &hmtxSharedSem ) ) != NO_ERROR )
      {
      printf( "DosOpenMutexSem rc = %lu\n", rc );
      return rc;
      }

   /* Acquire the shared mutex semaphore.                                     */

   if ( ( rc = DosRequestMutexSem( hmtxSharedSem,
                                   SEM_INDEFINITE_WAIT ) ) != NO_ERROR )
      {
      printf( "DosRequestMutexSem rc = %lu\n", rc );
      DosCloseMutexSem( hmtxSharedSem );
      return rc;
      }

   /* Increment the count of processes registered.                            */

   ++ulProcessCount;

   /* Initialize the per-process data.                                        */

   ulProcessTotal = 0;
   pidProcess = ppib->pib_ulpid;

   /* Tell the user that the current process has been registered.             */

   printf( "\nProcess %lu has been registered.\n\n", pidProcess );

   /* Release the shared mutex semaphore.                                     */

   if ( ( rc = DosReleaseMutexSem( hmtxSharedSem ) ) != NO_ERROR )
      {
      printf( "DosReleaseMutexSem rc = %lu\n", rc );
      return rc;
      }

   return 0;
   }

/* DLLINCREMENT - Increments the process and global totals on behalf of the   */
/*                calling program.                                            */

int DLLINCREMENT( int incount )
   {
   APIRET           rc;                     /* return code from DOS APIs      */

   /* Acquire the shared mutex semaphore.                                     */

   if ( ( rc = DosRequestMutexSem( hmtxSharedSem,
                                   SEM_INDEFINITE_WAIT ) ) != NO_ERROR )
      {
      printf( "DosRequestMutexSem rc = %lu\n", rc );
      return rc;
      }

   /* Increment the counts the process and grand totals.                      */

   ulProcessTotal += incount;
   ulGrandTotal += incount;

   /* Tell the user that the increment was successful.                        */

   printf( "\nThe increment for process %lu was successful.\n\n", pidProcess );

   /* Release the shared mutex semaphore.                                     */

   if ( ( rc = DosReleaseMutexSem( hmtxSharedSem ) ) != NO_ERROR )
      {
      printf( "DosReleaseMutexSem rc = %lu\n", rc );
      return rc;
      }

   return 0;
   }

/* DLLSTATS  - Prints process and grand totals.                               */

int DLLSTATS( void )
   {
   APIRET          rc;

   /* Acquire the shared mutex semaphore.                                     */

   if ( ( rc = DosRequestMutexSem( hmtxSharedSem,
                                   SEM_INDEFINITE_WAIT ) ) != NO_ERROR )
      {
      printf( "DosRequestMutexSem rc = %lu\n", rc );
      return rc;
      }

   /* Print out per-process and global information.                           */

   printf( "\nCurrent process identifier     = %lu\n", pidProcess );
   printf( "Current process total          = %lu\n", ulProcessTotal );
   printf( "Number of processes registered = %lu\n", ulProcessCount );
   printf( "Grand Total                    = %lu\n\n", ulGrandTotal );

   /* Release the shared mutex semaphore.                                     */

   if ( ( rc = DosReleaseMutexSem( hmtxSharedSem ) ) != NO_ERROR )
      {
      printf( "DosReleaseMutexSem rc = %lu\n", rc );
      return rc;
      }

   return 0;
   }

/* DLLDEREGISTER - Deregisters the current process from this subsystem.       */
/*                 Called by _DLL_InitTerm when the DLL is freed for the      */
/*                 last time by the current process.                          */

static unsigned long DLLDEREGISTER( void )
   {
   APIRET rc;

   /* Acquire the shared mutex semaphore.                                     */

   if ( ( rc = DosRequestMutexSem( hmtxSharedSem,
                                   SEM_INDEFINITE_WAIT ) ) != NO_ERROR )
      {
      printf( "DosRequestMutexSem rc = %lu\n", rc );
      return rc;
      }

   /* Decrement the count of processes registered.                            */

   --ulProcessCount;

   /* Tell the user that the current process has been deregistered.           */

   printf( "\nProcess %lu has been deregistered.\n\n", pidProcess );

   /* Release the shared mutex semaphore.                                     */

   if ( ( rc = DosReleaseMutexSem( hmtxSharedSem ) ) != NO_ERROR )
      {
      printf( "DosReleaseMutexSem rc = %lu\n", rc );
      return rc;
      }

   /* Close the shared mutex semaphore for this process.                      */

   if ( ( rc = DosCloseMutexSem( hmtxSharedSem ) ) != NO_ERROR )
      {
      printf( "DosCloseMutexSem rc = %lu\n", rc );
      return rc;
      }

   return 0;
   }
