Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

398 lines
9.6 KiB

//=================================================================
//
// ResourceManager.cpp
//
// Copyright (c) 1998-2002 Microsoft Corporation, All Rights Reserved
//
//=================================================================
/*
* Currently the implementations of std::_Lockit::_Lockit() are in framedyn.dll
* If this class is being used outside the scope of win32providers then an implementation of std::_Lockit::_Lockit() has to be provided
* by the client ( I think!) .
*/
#include "precomp.h"
#include <assertbreak.h>
#include "ResourceManager.h"
#include "ProvExce.h"
#include <comdef.h>
#include "TimerQueue.h"
// automatic crit sec
#include "cautolock.h"
//
// resource management failures
//
BOOL bAddInstanceCreatorFailure = FALSE ;
//initialize statics
/*
* All the resources not released by clients or cached in the ResourceManager are forcibly freed in the ResourceManager destructor.
* When a resource is freed , the resource tries to deregister the timeout rule from the TimerQueue, which means that the TimerQueue
* has to be present when the ResourceManager destructor is fired,else we'll have a crash on Win9x. --RAID 50454
*/
//CTimerQueue CTimerQueue :: s_TimerQueue ;
//CResourceManager CResourceManager::sm_TheResourceManager ;
CResourceManager :: CResourceManager ()
{
}
CResourceManager :: ~CResourceManager ()
{
std::list < CResourceList* >::iterator pInstanceList ;
/*
* Ideally, at this point of time when the global destructors get fired there should not be any resources in the resource manager,
* but if there are any , we've to forcibly delete them. We're safe in doing this becuase the scheduler thread would've exited already
* in DllCanUnloadNow & no other thread would be calling into the resource manager
*/
LogMessage ( L"Entering ~CResourceManager" ) ;
CAutoLock cs ( m_csResourceManager ) ;
while ( !m_Resources.empty () )
{
delete m_Resources.front() ;
m_Resources.pop_front() ;
}
cs.Exec () ;
LogMessage ( L"Leaving ~CResourceManager" ) ;
}
/*
* This method checks if we've any resource leak
*/
void CResourceManager :: ForcibleCleanUp ()
{
LogMessage ( L"Entering CResourceManager :: ForcibleCleanUp" ) ;
std::list < CResourceList* >::iterator pInstanceList ;
CAutoLock cs ( m_csResourceManager ) ;
for ( pInstanceList = m_Resources.begin () ; pInstanceList != m_Resources.end () ; pInstanceList++ )
{
( *pInstanceList )->ShutDown () ;
}
cs.Exec () ;
LogMessage ( L"Leaving CResourceManager :: ForcibleCleanUp" ) ;
}
CResource* CResourceManager :: GetResource ( GUID ResourceId, PVOID pData )
{
std::list < CResourceList* >::iterator pInstanceList ;
for ( pInstanceList = m_Resources.begin () ; pInstanceList != m_Resources.end () ; pInstanceList++ )
{
if ( IsEqualGUID ( (*pInstanceList)->guidResourceId, ResourceId ) )
{
return (*pInstanceList)->GetResource ( pData ) ;
}
}
return NULL ;
}
ULONG CResourceManager :: ReleaseResource ( GUID ResourceId, CResource* pResource )
{
std::list < CResourceList* >::iterator pInstanceList ;
for ( pInstanceList = m_Resources.begin () ; pInstanceList != m_Resources.end () ; pInstanceList++ )
{
if ( IsEqualGUID ( (*pInstanceList)->guidResourceId, ResourceId ) )
{
return (*pInstanceList)->ReleaseResource ( pResource ) ;
}
}
return ULONG ( -1 ) ;
}
BOOL CResourceManager :: AddInstanceCreator ( GUID ResourceId, PFN_RESOURCE_INSTANCE_CREATOR pfnResourceInstanceCreator )
{
CAutoLock cs ( m_csResourceManager ) ;
//create a node & add it
CResourceList *stResourceInstances = new CResourceList ;
if ( stResourceInstances == NULL )
{
throw CHeap_Exception( CHeap_Exception::E_ALLOCATION_ERROR ) ;
}
stResourceInstances->guidResourceId = ResourceId ;
stResourceInstances->m_pfnInstanceCreator = pfnResourceInstanceCreator ;
m_Resources.push_back ( stResourceInstances ) ;
return TRUE ;
}
CResourceList :: CResourceList ()
{
m_bShutDown = FALSE ;
}
CResourceList :: ~CResourceList ()
{
m_bShutDown = TRUE ;
ShutDown () ;
}
CResource* CResourceList :: GetResource ( LPVOID pData )
{
CResource* pTmpInstance = NULL ;
tagInstances::iterator ppInstance ;
BOOL bRet ;
//check if we're shutting down
if ( m_bShutDown )
{
return NULL ;
}
//Lock the list
CResourceListAutoLock cs ( this ) ;
//check if we're shutting down
if ( m_bShutDown )
{
return NULL ;
}
try
{
//go thru all the instances of this resource & hand out the first valid one
for ( ppInstance = m_Instances.begin(); ppInstance != m_Instances.end (); ppInstance++ )
{
//Check out if we've cached a similar instance
if ( ( *ppInstance )->IsOneOfMe ( pData ) )
{
//try to acquire the resource...this will up the refcount.
bRet = ( *ppInstance )->Acquire () ;
if ( bRet )
{
pTmpInstance = *ppInstance ;
break ; //got the instance so break
}
}
}
//if we haven't got a cached instance to hand out, create a new instance
if ( !pTmpInstance )
{
//this will create a new instance but the ref-count is still zero
pTmpInstance = m_pfnInstanceCreator ( pData ) ;
//Try to acquire the instance for the client ..which will up the ref-count
if ( pTmpInstance )
{
if ( pTmpInstance->IsValid () )
{
pTmpInstance->SetParent ( this ) ;
bRet = pTmpInstance->Acquire () ;
//if the acquire succeeded on the instance, add it to our list of cached instances
if ( bRet )
{
m_Instances.insert ( m_Instances.begin (), pTmpInstance ) ;
}
else
{
delete pTmpInstance ;
pTmpInstance = NULL ;
}
}
else
{
// set creation error as they can look for it
::SetLastError ( pTmpInstance->GetCreationError () );
delete pTmpInstance ;
pTmpInstance = NULL ;
}
}
}
}
catch ( ... )
{
if ( pTmpInstance )
{
delete pTmpInstance ;
pTmpInstance = NULL ;
}
throw ;
}
return pTmpInstance ;
}
ULONG CResourceList :: ReleaseResource ( CResource* pResource )
{
CResource* pTmpInstance = NULL ;
tagInstances::iterator ppInstance ;
LONG lCount = -1 ;
//check if we're shutting down
if ( m_bShutDown )
{
return NULL ;
}
//Lock the list
CResourceListAutoLock cs ( this ) ;
//check if we're shutting down
if ( m_bShutDown )
{
return lCount ;
}
//Go thru the list & release the resource
for ( ppInstance = m_Instances.begin(); ppInstance != m_Instances.end (); ppInstance++ )
{
if ( *ppInstance == pResource )
{
lCount = pResource->Release () ;
break ;
}
}
return lCount ;
}
//This function will be called by the CResource to remove it's entry from the list of instances. The resource should have a
//lock on the list before it attempts to do this
void CResourceList :: RemoveFromList ( CResource* pResource )
{
tagInstances::iterator ppInstance ;
//Go thru the list & remove the link to the resource
for ( ppInstance = m_Instances.begin(); ppInstance != m_Instances.end (); ppInstance++ )
{
if ( *ppInstance == pResource )
{
m_Instances.erase ( ppInstance ) ;
break ;
}
}
}
void CResourceList :: ShutDown ()
{
CResourceListAutoLock cs ( this ) ;
LPOLESTR t_pOleStr = NULL ;
CHString t_chsListGuid ;
if ( StringFromCLSID ( guidResourceId , &t_pOleStr ) == S_OK )
{
t_chsListGuid = t_pOleStr ;
CoTaskMemFree ( t_pOleStr ) ;
}
tagInstances::iterator ppInstance ;
//Go thru the list & remove the link to the resource
while ( !m_Instances.empty () )
{
#if (defined DEBUG || defined _DEBUG)
// Note that this COULD be because there is a timer rule, and the time hasn't expired
// before the DllCanUnloadNow function is called by com (that's who calls this function).
LogErrorMessage3 ( L"%s%s" , L"Resource not released before shutdown = " , t_chsListGuid ) ;
#endif
m_Instances.pop_front() ;
}
}
CResource :: CResource () :
m_bValid ( TRUE ),
m_dwCreationError ( ERROR_SUCCESS )
{
m_pRules = NULL ;
m_lRef = 0 ;
m_pResources = NULL ;
}
CResource :: ~CResource ()
{
}
//This function increments ref-count of the object & calls into the virtual overridables OnAcquire or OnInitialAcquire
//The derived class should override these functions if it wants to & decrement the ref-count if it wants the Acquire
//operation to fail
BOOL CResource::Acquire ()
{
BOOL bRet ;
++m_lRef ;
if ( m_lRef == 1 )
{
bRet = OnInitialAcquire () ;
}
else
{
bRet = OnAcquire () ;
}
if ( m_lRef == 0 )
{
m_pResources->RemoveFromList ( this ) ;
if ( m_pRules )
{
//since we're going away, we detach ourselves from the rule so that the rules don't call into us
m_pRules->Detach () ;
m_pRules->Release () ;
m_pRules = NULL ;
}
delete this ;
//we do not want to use instance which got deleted
bRet = FALSE;
}
return bRet ;
}
ULONG CResource::Release ()
{
BOOL bRet ;
ULONG lCount = 0 ;
--m_lRef ;
if ( m_lRef == 0 )
{
bRet = OnFinalRelease () ;
}
else
{
bRet = OnRelease () ;
}
if ( bRet )
{
if ( m_lRef == 0 )
{
m_pResources->RemoveFromList ( this ) ;
if ( m_pRules )
{
//since we're going away, we detach ourselves from the rule so that the rules don't call into us
m_pRules->Detach () ;
m_pRules->Release () ;
m_pRules = NULL ;
}
delete this ;
return lCount ;
}
}
return m_lRef ;
}
/*
void CResource :: RuleEvaluated ( const CRule *a_RuleEvaluated )
{
if ( m_pRules )
{
return m_pRules->CheckRule () ;
}
else
{
return FALSE ;
}
}
*/