Kernel-Mode
ADAPT Structure Reference Counting

Copyright © 2003 by Printing Communications Assoc., Inc. (PCAUSA). All rights reserved

First we add a RefCount member variable to the ADAPT structure.

Then we provide two functions that manipulate the RefCount:

We modify PtBindAdapter to set the initial ADAPT RefCount to 1. And finally we replace calls to NdisFreeMemory with calls to PtDerefAdapter in PtUnbindAdapter and MPHalt.

It is also worthwhile to note that PtDerefAdapter does more then simply free the memory being referenced. In the actual implementation of PtDerefAdapter we consolidate some duplicate code from PtUnbindAdapter and MPHalt into PtDerefAdapter.

 

Modified Code: PassThru.h Module, ADAPT Structure

typedef struct _ADAPT
{
    ...
    NDIS_STRING         DeviceName;               // For initializing the miniport edge
// BEGIN_PTUSERIO
    ULONG               RefCount;                 // Used For ADAPT Reference Counting
// END_PTUSERIO
    NDIS_EVENT          MiniportInitEvent;        // For blocking UnbindAdapter while
                                                  // an IM Init is in progress.
    ...
} ADAPT, *PADAPT;

 

New Code: PTExtend.c Module, PtRefAdapter and PtDerefAdapter Functions

These are the two ADAPT structure reference counting functions. In addition to managing when the ADAPT structure is freed we have absorbed additional redundant code from MPHalt and PtUnbindAdapter into PtDerefAdapter.

VOID
PtRefAdapter( PADAPT pAdapt )
{
   NdisInterlockedIncrement( &pAdapt->RefCount );
}
VOID
PtDerefAdapter( PADAPT pAdapt )
{
   if( !pAdapt )
   {
      return;
   }
   if( NdisInterlockedDecrement( &pAdapt->RefCount) == 0 )
   {
      DBGPRINT(( "PtDerefAdapter: Adapter: 0x%8.8X\n", pAdapt ? (ULONG )pAdapt : 0 ));
      //
      //  Free all resources on this adapter structure.
      //
      if (pAdapt->RecvPacketPoolHandle != NULL)
      {
         //
         // Free the packet pool that is used to indicate receives
         //
         NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);
         pAdapt->RecvPacketPoolHandle = NULL;
      }
      if (pAdapt->SendPacketPoolHandle != NULL)
      {
         //
         //  Free the packet pool that is used to send packets below
         //
         NdisFreePacketPool(pAdapt->SendPacketPoolHandle);
         pAdapt->SendPacketPoolHandle = NULL;
      }
      NdisFreeMemory(pAdapt, 0, 0);
   }
}

Modified Code: Protocol.c Module, PtBindAdapter Function

These modifications add the initial reference count to the ADAPT structure, In addition, the new PtDerefAddapter function is called instead of NdisFreeMemory in one place.

VOID
PtBindAdapter(
    OUT PNDIS_STATUS            Status,
    IN  NDIS_HANDLE             BindContext,
    IN  PNDIS_STRING            DeviceName,
    IN  PVOID                   SystemSpecific1,
    IN  PVOID                   SystemSpecific2
    )
{
    ...
    do
    {
        ...
        //
        // Initialize the adapter structure. We copy in the IM device
        // name as well, because we may need to use it in a call to
        // NdisIMCancelInitializeDeviceInstance. The string returned
        // by NdisReadConfiguration is active (i.e. available) only
        // for the duration of this call to our BindAdapter handler.
        //
        NdisZeroMemory(pAdapt, TotalSize);
        pAdapt->DeviceName.MaximumLength = Param->ParameterData.StringData.MaximumLength;
        pAdapt->DeviceName.Length = Param->ParameterData.StringData.Length;
        pAdapt->DeviceName.Buffer = (PWCHAR)((ULONG_PTR)pAdapt + sizeof(ADAPT));
        NdisMoveMemory(pAdapt->DeviceName.Buffer,
                       Param->ParameterData.StringData.Buffer,
                       Param->ParameterData.StringData.Length);
// BEGIN_PTUSERIO
        //
        // Add Initial Reference To Adapter
        //
        PtRefAdapter( pAdapt );
// END_PTUSERIO
        NdisInitializeEvent(&pAdapt->Event);
        NdisAllocateSpinLock(&pAdapt->Lock);
        ...
    } while(FALSE);
    ...
    if (*Status != NDIS_STATUS_SUCCESS)
    {
       if (pAdapt != NULL)
       {
         if (pAdapt->BindingHandle != NULL)
         {
            NDIS_STATUS    LocalStatus;
            //
            // Close the binding to the adapter
            //
            NdisResetEvent(&pAdapt->Event);
            NdisCloseAdapter(&LocalStatus, pAdapt->BindingHandle);
            pAdapt->BindingHandle = NULL;
            if (LocalStatus == NDIS_STATUS_PENDING)
            {
               NdisWaitEvent(&pAdapt->Event, 0);
               LocalStatus = pAdapt->Status;
            }
            ASSERT (LocalStatus == NDIS_STATUS_SUCCESS);
         }
// BEGIN_PTUSERIO
          //
          // Remove Protocol's Reference To The Adapter
          //
          PtDerefAdapter( pAdapt );
// END_PTUSERIO
          pAdapt = NULL;
       }
    }
}

 

Modified Code: Protocol.c Module, PtUnbindAdapter Function

These modifications show the call to the new PtDerefAddapter function is called instead of NdisFreeMemory. In addition, some common code shared between PtUnbindAdapter and MPHalt has been absorbed into PtDerefAdapter.

VOID
PtUnbindAdapter(
    OUT PNDIS_STATUS        Status,
    IN  NDIS_HANDLE            ProtocolBindingContext,
    IN  NDIS_HANDLE            UnbindContext
    )
{
    ...
    if (pAdapt->MiniportHandle != NULL)
    {
        *Status = NdisIMDeInitializeDeviceInstance(pAdapt->MiniportHandle);
        if (*Status != NDIS_STATUS_SUCCESS)
        {
            *Status = NDIS_STATUS_FAILURE;
        }
    }
    else
    {
        //
        // We need to do some work here. 
        // Close the binding below us 
        // and release the memory allocated.
        //
        if(pAdapt->BindingHandle != NULL)
        {
            NdisResetEvent(&pAdapt->Event);
            NdisCloseAdapter(Status, pAdapt->BindingHandle);
            //
            // Wait for it to complete
            //
            if(*Status == NDIS_STATUS_PENDING)
            {
                 NdisWaitEvent(&pAdapt->Event, 0);
                 *Status = pAdapt->Status;
            }
            pAdapt->BindingHandle = NULL;
        }
        else
        {
            //
            // Both Our MiniportHandle and Binding Handle  should not be NULL.
            //
            *Status = NDIS_STATUS_FAILURE;
            ASSERT(0);
        }
// BEGIN_PTUSERIO
        //
        //    Free the memory here, if was not released earlier(by calling the HaltHandler)
        //
        PtDerefAdapter( pAdapt );
// END_PTUSERIO
    }
    DBGPRINT(("<== PtUnbindAdapter: Adapt %p\n", pAdapt));
}

 

Modified Code: Miniport.c Module, MPHalt Function

These modifications show the call to the new PtDerefAddapter function is called instead of NdisFreeMemory. In addition, some common code shared between PtUnbindAdapter and MPHalt has been absorbed into PtDerefAdapter.

VOID
MPHalt(
    IN NDIS_HANDLE                MiniportAdapterContext
    )
{
    ...
    //
    // Delete the ioctl interface that was created when the miniport
    // was created.
    //
    (VOID)PtDeregisterDevice();
    if (pAdapt->BindingHandle != NULL)
    {
      NDIS_STATUS    LocalStatus;
      //
      // Close the binding to the adapter
      //
      NdisResetEvent(&pAdapt->Event);
      NdisCloseAdapter(&LocalStatus, pAdapt->BindingHandle);
      pAdapt->BindingHandle = NULL;
      if (LocalStatus == NDIS_STATUS_PENDING)
      {
         NdisWaitEvent(&pAdapt->Event, 0);
         LocalStatus = pAdapt->Status;
      }
      ASSERT (LocalStatus == NDIS_STATUS_SUCCESS);
    }
// BEGIN_PTUSERIO
   //
   // Remove Miniport's Reference To The Adapter
   //
   PtDerefAdapter( pAdapt );
// END_PTUSERIO
    DBGPRINT(("<== MiniportHalt: pAdapt %p\n", pAdapt));
}