windows-nt/Source/XPSP1/NT/admin/wmi/wbem/common/containers/cache.cpp
2020-09-26 16:20:57 +08:00

955 lines
19 KiB
C++

#ifndef __CACHE_CPP
#define __CACHE_CPP
/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
Thread.cpp
Abstract:
Enhancements to current functionality:
Timeout mechanism should track across waits.
AddRef/Release on task when scheduling.
Enhancement Ticker logic.
History:
--*/
#include <HelperFuncs.h>
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
LONG operator == ( const WmiCacheController <WmiKey> :: WmiUniqueTimeout &a_Arg1 , const WmiCacheController <WmiKey> :: WmiUniqueTimeout &a_Arg2 )
{
LONG t_Compare ;
if ( ( t_Compare = a_Arg1.GetTicks () - a_Arg2.GetTicks () ) == 0 )
{
t_Compare = a_Arg1.GetCounter () - a_Arg2.GetCounter () ;
}
return t_Compare == 0 ? true : false ;
}
template <class WmiKey>
bool operator < ( const WmiCacheController <WmiKey> :: WmiUniqueTimeout &a_Arg1 , const WmiCacheController <WmiKey> :: WmiUniqueTimeout &a_Arg2 )
{
LONG t_Compare ;
if ( ( t_Compare = a_Arg1.GetTicks () - a_Arg2.GetTicks () ) == 0 )
{
t_Compare = a_Arg1.GetCounter () - a_Arg2.GetCounter () ;
}
return t_Compare < 0 ? true : false ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiCacheController <WmiKey> :: WmiCacheController (
WmiAllocator &a_Allocator
) : m_Allocator ( a_Allocator ) ,
m_Cache ( a_Allocator ) ,
m_CacheDecay ( a_Allocator ) ,
m_ReferenceCount ( 0 ) ,
m_Counter ( 0 ),
m_CriticalSection(NOTHROW_LOCK)
{
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiCacheController <WmiKey> :: ~WmiCacheController ()
{
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
STDMETHODIMP_( ULONG ) WmiCacheController <WmiKey> :: AddRef ()
{
return InterlockedIncrement ( & m_ReferenceCount ) ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
STDMETHODIMP_( ULONG ) WmiCacheController <WmiKey> :: Release ()
{
ULONG t_ReferenceCount = InterlockedDecrement ( & m_ReferenceCount ) ;
if ( t_ReferenceCount == 0 )
{
delete this ;
}
return t_ReferenceCount ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
STDMETHODIMP WmiCacheController <WmiKey> :: QueryInterface ( REFIID , LPVOID FAR * )
{
return E_NOINTERFACE ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Initialize ()
{
WmiStatusCode t_StatusCode = m_Cache.Initialize () ;
if ( t_StatusCode == e_StatusCode_Success )
{
t_StatusCode = m_CacheDecay.Initialize () ;
if ( t_StatusCode == e_StatusCode_Success )
{
t_StatusCode = WmiHelper :: InitializeCriticalSection ( & m_CriticalSection ) ;
}
}
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: UnInitialize ()
{
WmiStatusCode t_StatusCode = m_Cache.UnInitialize () ;
if ( t_StatusCode == e_StatusCode_Success )
{
t_StatusCode = m_CacheDecay.UnInitialize () ;
}
WmiHelper :: DeleteCriticalSection ( & m_CriticalSection ) ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Insert (
WmiCacheElement &a_Element ,
Cache_Iterator &a_Iterator
)
{
WmiStatusCode t_StatusCode = e_StatusCode_Success ;
Lock () ;
Cache_Iterator t_Iterator ;
t_StatusCode = m_Cache.Insert ( a_Element.GetKey () , & a_Element , t_Iterator ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
a_Element.InternalAddRef () ;
a_Element.SetCached ( TRUE ) ;
}
UnLock () ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Delete (
const WmiKey &a_Key
)
{
Lock () ;
WmiStatusCode t_StatusCode = m_Cache.Delete ( a_Key ) ;
UnLock () ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Find (
const WmiKey &a_Key ,
Cache_Iterator &a_Iterator
)
{
Lock () ;
WmiStatusCode t_StatusCode = m_Cache.Find ( a_Key , a_Iterator ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
a_Iterator.GetElement ()->AddRef ( ) ;
}
UnLock () ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Lock ()
{
WmiStatusCode t_StatusCode = WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: UnLock ()
{
WmiStatusCode t_StatusCode = WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Shutdown ()
{
Lock () ;
ULONG t_Index = 0 ;
while ( true )
{
WmiUniqueTimeout t_Key ;
WmiCacheElement *t_Element = NULL ;
WmiStatusCode t_StatusCode = m_CacheDecay.Top ( t_Key , t_Element ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
t_Index ++ ;
t_StatusCode = m_CacheDecay.DeQueue () ;
}
else
{
break ;
}
}
ULONG t_ElementCount = m_Cache.Size () ;
WmiCacheElement **t_Elements = NULL ;
WmiStatusCode t_StatusCode = m_Allocator.New (
( void ** ) & t_Elements ,
sizeof ( WmiCacheElement ) * t_ElementCount
) ;
if ( t_StatusCode == e_StatusCode_Success )
{
for ( ULONG t_Index = 0 ; t_Index < t_ElementCount ; t_Index ++ )
{
t_Elements [ t_Index ] = NULL ;
}
ULONG t_ElementIndex = 0 ;
Cache_Iterator t_Iterator = m_Cache.Root ();
while ( ! t_Iterator.Null () )
{
if ( t_Iterator.GetElement ()->GetDecayed () == FALSE )
{
WmiCacheElement *t_Element = t_Iterator.GetElement () ;
t_Elements [ t_ElementIndex ] = t_Element ;
t_Element->SetDecayed ( TRUE ) ;
t_Element->SetDecaying ( FALSE ) ;
t_Element->SetCached ( FALSE ) ;
m_Cache.Delete ( t_Iterator.GetKey () ) ;
}
else
{
m_Cache.Delete ( t_Iterator.GetKey () ) ;
}
t_ElementIndex ++ ;
t_Iterator = m_Cache.Root () ;
}
}
UnLock () ;
if ( t_Elements )
{
for ( ULONG t_Index = 0 ; t_Index < t_ElementCount ; t_Index ++ )
{
if ( t_Elements [ t_Index ] )
{
t_Elements [ t_Index ]->InternalRelease () ;
}
}
m_Allocator.Delete ( t_Elements ) ;
}
return e_StatusCode_Success ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Shutdown ( const WmiKey &a_Key )
{
Lock () ;
Cache_Iterator t_Iterator ;
WmiStatusCode t_StatusCode = m_Cache.Find ( a_Key , t_Iterator ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
if ( t_Iterator.GetElement ()->GetDecayed () == FALSE )
{
CacheDecay_Iterator t_QueueIterator = m_CacheDecay.Begin () ;
while ( ! t_QueueIterator.Null () )
{
WmiCacheElement *t_Element = t_QueueIterator.GetElement () ;
if ( t_Element == t_Iterator.GetElement () )
{
m_CacheDecay.Delete ( t_QueueIterator.GetKey () ) ;
break ;
}
t_QueueIterator.Increment () ;
}
WmiCacheElement *t_Element = t_Iterator.GetElement () ;
t_Element->SetDecayed ( TRUE ) ;
t_Element->SetDecaying ( FALSE ) ;
t_Element->SetCached ( FALSE ) ;
m_Cache.Delete ( a_Key ) ;
UnLock () ;
t_Element->InternalRelease () ;
}
else
{
m_Cache.Delete ( a_Key ) ;
UnLock () ;
}
}
else
{
UnLock () ;
}
return e_StatusCode_Success ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: StrobeBegin ( const ULONG &a_Timeout )
{
return e_StatusCode_Success ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Strobe ( ULONG &a_NextStrobeDelta )
{
while ( true )
{
Lock () ;
WmiUniqueTimeout t_Key ;
WmiCacheElement *t_Element = NULL ;
WmiStatusCode t_StatusCode = m_CacheDecay.Top ( t_Key , t_Element ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
a_NextStrobeDelta = ( a_NextStrobeDelta < t_Element->GetPeriod () ) ? a_NextStrobeDelta : t_Element->GetPeriod () ;
ULONG t_Ticks = GetTickCount () ;
#if 0
wchar_t t_Buffer [ 128 ] ;
wsprintf ( t_Buffer , L"\n%lx - Checking ( %lx , %lx ) " , t_Ticks , t_Element , t_Key.GetTicks () ) ;
OutputDebugString ( t_Buffer ) ;
#endif
if ( t_Ticks >= t_Key.GetTicks () )
{
if ( t_Element->GetDecaying () )
{
#if 0
wchar_t t_Buffer [ 128 ] ;
wsprintf ( t_Buffer , L"\n%lx - Strobe ( %lx , %lx ) " , t_Ticks , t_Element , t_Key.GetTicks () ) ;
OutputDebugString ( t_Buffer ) ;
#endif
t_Element->SetDecaying ( FALSE ) ;
t_Element->SetDecayed ( TRUE ) ;
t_StatusCode = m_CacheDecay.DeQueue () ;
UnLock () ;
t_Element->InternalRelease () ;
}
else
{
t_StatusCode = m_CacheDecay.DeQueue () ;
UnLock () ;
}
}
else
{
UnLock () ;
break ;
}
}
else
{
UnLock () ;
break ;
}
}
return e_StatusCode_Success ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiCacheController <WmiKey> :: Decay (
WmiCacheElement &a_Element
)
{
Lock () ;
ULONG t_Size = m_CacheDecay.Size () ;
Cache_Iterator t_Iterator ;
WmiStatusCode t_StatusCode = m_Cache.Find ( a_Element.GetKey () , t_Iterator ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
BOOL t_Found = FALSE ;
CacheDecay_Iterator t_QueueIterator = m_CacheDecay.Begin () ;
while ( ! t_QueueIterator.Null () )
{
WmiCacheElement *t_Element = t_QueueIterator.GetElement () ;
if ( t_Element == & a_Element )
{
m_CacheDecay.Delete ( t_QueueIterator.GetKey () ) ;
break ;
}
t_QueueIterator.Increment () ;
}
ULONG t_Ticks = GetTickCount () ;
WmiUniqueTimeout t_Key (
t_Ticks + a_Element.GetPeriod () ,
InterlockedIncrement ( & m_Counter )
) ;
#if 0
wchar_t t_Buffer [ 128 ] ;
wsprintf ( t_Buffer , L"\n%lx - Decaying ( %lx , %lx , %lx ) " , t_Ticks , & a_Element , t_Ticks + a_Element.GetPeriod () , a_Element.GetPeriod () ) ;
OutputDebugString ( t_Buffer ) ;
#endif
t_StatusCode = m_CacheDecay.EnQueue (
t_Key ,
t_Iterator.GetElement ()
) ;
UnLock () ;
if ( t_Size == 0 )
{
StrobeBegin ( a_Element.GetPeriod () ) ;
}
if ( t_StatusCode != e_StatusCode_Success )
{
a_Element.InternalRelease () ;
}
}
else
{
UnLock () ;
}
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiContainerController <WmiKey> :: WmiContainerController (
WmiAllocator &a_Allocator
) : m_Container ( a_Allocator ) ,
m_ReferenceCount ( 0 ),
m_CriticalSection(NOTHROW_LOCK)
{
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiContainerController <WmiKey> :: ~WmiContainerController ()
{
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
STDMETHODIMP_( ULONG ) WmiContainerController <WmiKey> :: AddRef ()
{
return InterlockedIncrement ( & m_ReferenceCount ) ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
STDMETHODIMP_( ULONG ) WmiContainerController <WmiKey> :: Release ()
{
ULONG t_ReferenceCount = InterlockedDecrement ( & m_ReferenceCount ) ;
if ( t_ReferenceCount == 0 )
{
delete this ;
}
return t_ReferenceCount ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
STDMETHODIMP WmiContainerController <WmiKey> :: QueryInterface ( REFIID , LPVOID FAR * )
{
return E_NOINTERFACE ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Initialize ()
{
WmiStatusCode t_StatusCode = m_Container.Initialize () ;
if ( t_StatusCode == e_StatusCode_Success )
{
t_StatusCode = WmiHelper :: InitializeCriticalSection ( & m_CriticalSection ) ;
}
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: UnInitialize ()
{
WmiStatusCode t_StatusCode = m_Container.UnInitialize () ;
if ( t_StatusCode == e_StatusCode_Success )
{
t_StatusCode = WmiHelper :: DeleteCriticalSection ( & m_CriticalSection ) ;
}
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Insert (
WmiContainerElement &a_Element ,
Container_Iterator &a_Iterator
)
{
WmiStatusCode t_StatusCode = e_StatusCode_Success ;
Lock () ;
Container_Iterator t_Iterator ;
t_StatusCode = m_Container.Insert ( a_Element.GetKey () , & a_Element , t_Iterator ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
a_Element.InternalAddRef () ;
a_Element.SetCached ( TRUE ) ;
}
UnLock () ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Delete (
const WmiKey &a_Key
)
{
Lock () ;
WmiStatusCode t_StatusCode = m_Container.Delete ( a_Key ) ;
UnLock () ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Find (
const WmiKey &a_Key ,
Container_Iterator &a_Iterator
)
{
Lock () ;
WmiStatusCode t_StatusCode = m_Container.Find ( a_Key , a_Iterator ) ;
if ( t_StatusCode == e_StatusCode_Success )
{
a_Iterator.GetElement ()->AddRef ( ) ;
}
UnLock () ;
return t_StatusCode ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Lock ()
{
return WmiHelper :: EnterCriticalSection ( & m_CriticalSection ) ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: UnLock ()
{
WmiHelper :: LeaveCriticalSection ( & m_CriticalSection ) ;
return e_StatusCode_Success ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Shutdown ()
{
Lock () ;
Container_Iterator t_Iterator = m_Container.Root ();
while ( ! t_Iterator.Null () )
{
m_Container.Delete ( t_Iterator.GetKey () ) ;
t_Iterator = m_Container.Root () ;
}
UnLock () ;
return e_StatusCode_Success ;
}
/******************************************************************************
*
* Name:
*
*
* Description:
*
*
*****************************************************************************/
template <class WmiKey>
WmiStatusCode WmiContainerController <WmiKey> :: Strobe ( ULONG &a_NextStrobeDelta )
{
return e_StatusCode_Success ;
}
#endif __CACHE_CPP