windows-nt/Source/XPSP1/NT/net/dlc/driver/refcnt.c
2020-09-26 16:20:57 +08:00

245 lines
5.4 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
refcnt.c
Abstract:
This module contains checked reference counting support functions.
The free versions are inline.
Author:
Scott Holden (sholden) 12/29/1998 Borrowed from IrDA.
Revision History:
--*/
#ifdef NDIS40 // Only used for NDIS40 code now.
#if DBG
//
// Include Files
//
#include "dlc.h"
#include "llc.h"
#include "dbgmsg.h"
#define EXPAND_TAG(_Tag) ((CHAR *)(&_Tag))[0], \
((CHAR *)(&_Tag))[1], \
((CHAR *)(&_Tag))[2], \
((CHAR *)(&_Tag))[3]
VOID
ReferenceInitDbg(
IN PREF_CNT pRefCnt,
PVOID InstanceHandle,
VOID (*DeleteHandler)(PVOID pvContext),
ULONG TypeTag
)
/*++
Routine Description:
Initializes the reference control block. Reference count is initialized
to zero.
Arguments:
pRefCnt - pointer to uninitialized Reference Control Block
InstanceHandle - handle to the managed instance.
DeleteHandler - pointer to delete function, NULL is OK.
TypeTag - Identifies initialization.
Return Value:
The function's value is VOID.
--*/
{
DEBUGMSG(DBG_REF, (TEXT("ReferenceInit(%#x, %#x, %#x, %c%c%c%c)\n"),
pRefCnt, InstanceHandle, DeleteHandler, EXPAND_TAG(TypeTag)));
ASSERT(pRefCnt);
//
// Set the reference to 0 and save the instance
// handle and the delete handler.
//
pRefCnt->Count = 0;
pRefCnt->Instance = InstanceHandle;
pRefCnt->DeleteHandler = DeleteHandler;
pRefCnt->Sig = REF_SIG;
RtlZeroMemory(pRefCnt->Tags, sizeof(REF_TAG) * TAG_CNT);
pRefCnt->Tags[0].Tag = 'LTOT';
KeInitializeSpinLock(&pRefCnt->Lock);
pRefCnt->TypeTag = TypeTag;
return;
}
VOID
ReferenceAddDbg(
PREF_CNT pRefCnt,
ULONG Tag,
int cLine
)
{
int i;
int TotalPerArray = 0;
KIRQL OldIrql;
ASSERT(pRefCnt->Sig == REF_SIG);
DEBUGMSG(DBG_REF && DBG_VERBOSE, (TEXT("REFADD %#x [%c%c%c%c:%c%c%c%c] %d [l:%d]\n"),
pRefCnt, EXPAND_TAG(pRefCnt->TypeTag), EXPAND_TAG(Tag),
pRefCnt->Count, cLine));
KeAcquireSpinLock(&pRefCnt->Lock, &OldIrql);
for (i = 1; i < TAG_CNT; i++)
{
if (pRefCnt->Tags[i].Tag == 0 || pRefCnt->Tags[i].Tag == Tag)
{
pRefCnt->Tags[i].Tag = Tag;
InterlockedIncrement(&pRefCnt->Tags[i].Count);
break;
}
}
ASSERT(i < TAG_CNT);
InterlockedIncrement(&pRefCnt->Tags[0].Count);
InterlockedIncrement(&pRefCnt->Count);
ASSERT(pRefCnt->Tags[0].Count == pRefCnt->Count);
#ifdef REFCNT_SANITY_CHECK
for (i = 1; i < TAG_CNT; i++)
{
if (pRefCnt->Tags[i].Tag != 0)
{
TotalPerArray += pRefCnt->Tags[i].Count;
continue;
}
}
ASSERT(TotalPerArray == pRefCnt->Tags[0].Count);
if (TotalPerArray != pRefCnt->Tags[0].Count)
{
DbgBreakPoint();
}
#endif // REFCNT_SANITY_CHECK
KeReleaseSpinLock(&pRefCnt->Lock, OldIrql);
}
VOID
ReferenceRemoveDbg(
PREF_CNT pRefCnt,
ULONG Tag,
int cLine)
{
int i;
KIRQL OldIrql;
int TotalPerArray = 0;
BOOLEAN FoundIt = FALSE;
ASSERT(pRefCnt->Sig == REF_SIG);
KeAcquireSpinLock(&pRefCnt->Lock, &OldIrql);
DEBUGMSG(DBG_REF && DBG_VERBOSE, (TEXT("REFDEL %#x [%c%c%c%c:%c%c%c%c] %d [l:%d]\n"),
pRefCnt, EXPAND_TAG(pRefCnt->TypeTag), EXPAND_TAG(Tag),
pRefCnt->Count, cLine));
for (i = 1; i < TAG_CNT; i++)
{
if (pRefCnt->Tags[i].Tag == Tag)
{
FoundIt = TRUE;
ASSERT(pRefCnt->Tags[i].Count > 0);
InterlockedDecrement(&pRefCnt->Tags[i].Count);
if (pRefCnt->Tags[i].Count == 0)
{
pRefCnt->Tags[i].Tag = Tag;
}
break;
}
}
ASSERT(FoundIt);
ASSERT(pRefCnt->Tags[0].Count > 0);
ASSERT(pRefCnt->Tags[0].Count == pRefCnt->Count);
InterlockedDecrement(&pRefCnt->Tags[0].Count);
//
// If the decremented count is non zero return the instance handle.
//
//
// If reference is zero and delete handler is available, then call
// handler.
//
if (InterlockedDecrement(&pRefCnt->Count) <= 0 &&
pRefCnt->DeleteHandler)
{
DEBUGMSG(DBG_REF,(TEXT("REFDEL %#x [%c%c%c%c:%c%c%c%c] calling delete handler [l:%d].\n"),
pRefCnt, EXPAND_TAG(pRefCnt->TypeTag), EXPAND_TAG(Tag), cLine));
KeReleaseSpinLock(&pRefCnt->Lock, OldIrql);
(pRefCnt->DeleteHandler)(pRefCnt->Instance);
}
else
{
KeReleaseSpinLock(&pRefCnt->Lock, OldIrql);
}
#ifdef REFCNT_SANITY_CHECK
for (i = 1; i < TAG_CNT; i++)
{
if (pRefCnt->Tags[i].Tag != 0)
{
TotalPerArray += pRefCnt->Tags[i].Count;
continue;
}
}
ASSERT(TotalPerArray == pRefCnt->Tags[0].Count);
if (TotalPerArray != pRefCnt->Tags[0].Count)
{
DbgPrint(TEXT("Tag %X, RefCnt %X, perArray %d, total %d\n"), Tag, pRefCnt,
TotalPerArray, pRefCnt->Tags[0].Count);
DbgBreakPoint();
}
#endif // REFCNT_SANITY_CHECK
}
#endif // DBG
#endif // NDIS40