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.
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;
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); } }
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; } } }
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)); }
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)); }