414 lines
7.6 KiB
C
414 lines
7.6 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
refcnt.c
|
|
|
|
Abstract:
|
|
|
|
This module exports Reference Counting support functions. By
|
|
including a Reference Count Control Block (REF_CNT) in a
|
|
dynamic type, and using this API, a Reference scheme can be
|
|
implemented for that type.
|
|
|
|
Author:
|
|
|
|
Shreedhar Madhavapeddi (ShreeM) 15-March-1999
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Include Files
|
|
//
|
|
|
|
#include "precomp.h"
|
|
|
|
#define EXPAND_TAG(t) ((CHAR *)(&Tag))[0],((CHAR *)(&Tag))[1],((CHAR *)(&Tag))[2],((CHAR *)(&Tag))[3]
|
|
VOID
|
|
ReferenceInit
|
|
(
|
|
IN PREF_CNT pRefCnt,
|
|
PVOID InstanceHandle,
|
|
VOID (*DeleteHandler)( PVOID )
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ReferenceInit initializes and adds one reference to the
|
|
supplied Reference Control Block. If provided, an instance
|
|
handle and delete handler are saved for use by the ReferenceRemove
|
|
function when all references to the instance are removed.
|
|
|
|
Arguments:
|
|
|
|
pRefCnt - pointer to uninitialized Reference Control Block
|
|
InstanceHandle - handle to the managed instance.
|
|
DeleteHandler - pointer to delete function, NULL is OK.
|
|
|
|
Return Value:
|
|
|
|
The function's value is VOID.
|
|
|
|
--*/
|
|
|
|
{
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(( "ReferenceInit( 0x%x, 0x%x, 0x%x )\n",
|
|
pRefCnt, InstanceHandle, DeleteHandler ));
|
|
}
|
|
|
|
ASSERT( pRefCnt );
|
|
|
|
// Set the reference to 1 and save the instance
|
|
// handle and the delete handler.
|
|
|
|
pRefCnt->Count = 0;
|
|
pRefCnt->Instance = InstanceHandle;
|
|
pRefCnt->DeleteHandler = DeleteHandler;
|
|
|
|
#if DBG
|
|
pRefCnt->Sig = REF_SIG;
|
|
RtlZeroMemory(pRefCnt->Tags, sizeof(REF_TAG) * TAG_CNT);
|
|
pRefCnt->Tags[0].Tag = 'LTOT';
|
|
RefInitLock(pRefCnt->Lock);
|
|
#endif
|
|
|
|
}
|
|
|
|
VOID
|
|
ReferenceAdd
|
|
(
|
|
IN PREF_CNT pRefCnt
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ASSERT( pRefCnt );
|
|
|
|
InterlockedIncrement(&pRefCnt->Count);
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(( "R+%d\n", pRefCnt->Count ));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ReferenceAddCount
|
|
(
|
|
IN PREF_CNT pRefCnt,
|
|
IN UINT Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ASSERT( pRefCnt->Count > 0 );
|
|
InterlockedExchangeAdd(&pRefCnt->Count, Count);
|
|
|
|
}
|
|
|
|
PVOID
|
|
ReferenceRemove
|
|
(
|
|
IN PREF_CNT pRefCnt
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Arguments:
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Count;
|
|
UINT NoReference;
|
|
UINT i;
|
|
PVOID pInstance;
|
|
|
|
ASSERT( pRefCnt );
|
|
|
|
// Trap remove reference on a zero count
|
|
ASSERT(pRefCnt->Count>0);
|
|
|
|
pInstance = pRefCnt->Instance;
|
|
|
|
//ASSERT( pRefCnt->Count > 0 );
|
|
|
|
// If the decremented count is non zero return the instance handle
|
|
|
|
if (InterlockedDecrement(&pRefCnt->Count) > 0 )
|
|
{
|
|
|
|
IF_DEBUG(REFCOUNTX) {
|
|
|
|
WSPRINT(( "R-%d\n", pRefCnt->Count ));
|
|
WSPRINT(( "ReferenceRemove:remaining: %d\n", pRefCnt->Count ));
|
|
|
|
}
|
|
#if DBG
|
|
|
|
RefFreeLock(pRefCnt->Lock);
|
|
|
|
#endif
|
|
|
|
return(pInstance);
|
|
|
|
}
|
|
|
|
// Delete this instance if a delete handler is available
|
|
if( pRefCnt->DeleteHandler )
|
|
{
|
|
|
|
|
|
#if DBG
|
|
// sanity check
|
|
for (i = 1; i < TAG_CNT; i++)
|
|
{
|
|
if ((pRefCnt->Tags[i].Tag != 0) && (pRefCnt->Tags[i].Count != 0))
|
|
{
|
|
IF_DEBUG(ERRORS) {
|
|
WSPRINT(("Allors!! There is a NON-zero ref and we are deleting...\n"));
|
|
}
|
|
DEBUGBREAK();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(( "Executing DeleteHandler for %X\n", pRefCnt->Instance ));
|
|
}
|
|
|
|
//
|
|
// All the Dereference* code takes the locks, so lets take it here.
|
|
// Also, Take the global lock before releasing the ref lock.
|
|
//
|
|
|
|
// Time to delete the ref lock too.
|
|
RefFreeLock(pRefCnt->Lock);
|
|
#endif
|
|
|
|
GetLock(pGlobals->Lock);
|
|
|
|
#if DBG
|
|
RefDeleteLock(pRefCnt->Lock);
|
|
#endif
|
|
|
|
|
|
(pRefCnt->DeleteHandler)( pRefCnt->Instance );
|
|
FreeLock(pGlobals->Lock);
|
|
|
|
}
|
|
|
|
// Indicate no active references to this instance
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
//
|
|
// API Test Support
|
|
//
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
ReferenceApiTest( VOID )
|
|
{
|
|
REF_CNT RefCnt;
|
|
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(
|
|
( "\nReferenceApiTest\n" ));
|
|
|
|
WSPRINT(( "\nTest #1: NULL delete handler\n" ));
|
|
}
|
|
|
|
ReferenceInit( &RefCnt, &RefCnt, NULL );
|
|
|
|
ReferenceAdd( &RefCnt );
|
|
ReferenceAdd( &RefCnt );
|
|
ReferenceAdd( &RefCnt );
|
|
|
|
while( ReferenceRemove( &RefCnt ) )
|
|
{
|
|
;
|
|
}
|
|
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(( "\nTest #2: Delete Handler - TBD\n" ));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ReferenceAddDbg(PREF_CNT pRefCnt, ULONG Tag)
|
|
{
|
|
int i;
|
|
int TotalPerArray = 0;
|
|
|
|
RefGetLock(pRefCnt->Lock);
|
|
//ASSERT(pRefCnt->Sig == REF_SIG);
|
|
if (pRefCnt->Sig != REF_SIG) {
|
|
DEBUGBREAK();
|
|
}
|
|
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(("TCREF: add %X (%c%c%c%c) %d\n",
|
|
pRefCnt, EXPAND_TAG(Tag), pRefCnt->Count));
|
|
}
|
|
|
|
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);
|
|
if (i >= TAG_CNT) {
|
|
|
|
DEBUGBREAK();
|
|
|
|
}
|
|
|
|
ReferenceAdd(pRefCnt);
|
|
|
|
InterlockedIncrement(&pRefCnt->Tags[0].Count);
|
|
|
|
// 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();
|
|
}
|
|
|
|
|
|
|
|
RefFreeLock(pRefCnt->Lock);
|
|
}
|
|
|
|
VOID
|
|
ReferenceRemoveDbg(PREF_CNT pRefCnt, ULONG Tag)
|
|
{
|
|
int i;
|
|
int TotalPerArray = 0;
|
|
BOOLEAN FoundIt = FALSE;
|
|
|
|
RefGetLock(pRefCnt->Lock);
|
|
|
|
if (pRefCnt->Sig != REF_SIG) {
|
|
DEBUGBREAK();
|
|
}
|
|
|
|
//ASSERT(pRefCnt->Sig == REF_SIG);
|
|
|
|
IF_DEBUG(REFCOUNTX) {
|
|
WSPRINT(("TCREF: remove %X (%c%c%c%c) %d\n",
|
|
pRefCnt, EXPAND_TAG(Tag), pRefCnt->Count));
|
|
}
|
|
|
|
for (i = 1; i < TAG_CNT; i++)
|
|
{
|
|
if (pRefCnt->Tags[i].Tag == Tag)
|
|
{
|
|
FoundIt = TRUE;
|
|
|
|
if(pRefCnt->Tags[i].Count <= 0) {
|
|
|
|
DEBUGBREAK();
|
|
|
|
}
|
|
//ASSERT(pRefCnt->Tags[i].Count > 0);
|
|
InterlockedDecrement(&pRefCnt->Tags[i].Count);
|
|
if (pRefCnt->Tags[i].Count == 0)
|
|
pRefCnt->Tags[i].Tag = Tag;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!FoundIt) {
|
|
DEBUGBREAK();
|
|
}
|
|
|
|
ASSERT(FoundIt);
|
|
|
|
ASSERT(pRefCnt->Tags[0].Count > 0);
|
|
|
|
InterlockedDecrement(&pRefCnt->Tags[0].Count);
|
|
|
|
// 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("Tag %X, RefCnt %X, perArray %d, total %d\n", Tag, pRefCnt,
|
|
TotalPerArray, pRefCnt->Tags[0].Count);
|
|
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
|
|
|
|
ReferenceRemove(pRefCnt);
|
|
|
|
|
|
}
|
|
|
|
#endif
|