windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/ess3/essutils.cpp
2020-09-26 16:20:57 +08:00

227 lines
6.1 KiB
C++

//******************************************************************************
//
// ESSUTILS.CPP
//
// Copyright (C) 1996-1999 Microsoft Corporation
//
//******************************************************************************
#include "precomp.h"
#include <stdio.h>
#include "ess.h"
#include "essutils.h"
#include <tls.h>
CTLS g_tlsContext;
long g_lNumExternalThreadObjects = 0;
INTERNAL CEssThreadObject* GetCurrentEssThreadObject()
{
CEssThreadObject* pObj = (CEssThreadObject*)g_tlsContext.Get();
if ( pObj != NULL )
{
//
// mark the fact that we are handing the thread object to the
// outside world. We use this later on when checking
// thread object leaks.
//
pObj->SetReferencedExternally();
}
return pObj;
}
void SetCurrentEssThreadObject(IWbemContext* pContext)
{
//
// make sure we're not overwriting an existing internal thread object.
// if its externally referenced, we really can't tell if this would
// be a leak or not.
//
CEssThreadObject* pOldObj = (CEssThreadObject*)g_tlsContext.Get();
_DBG_ASSERT( pOldObj == NULL || pOldObj->IsReferencedExternally() );
CEssThreadObject* pObj = new CEssThreadObject(pContext);
g_tlsContext.Set((void*)pObj);
}
void SetConstructedEssThreadObject(CEssThreadObject* pObj)
{
//
// make sure we're not overwriting an existing internal thread object.
// if its externally referenced, we really can't tell if this would
// be a leak or not.
//
CEssThreadObject* pOldObj = (CEssThreadObject*)g_tlsContext.Get();
_DBG_ASSERT( pOldObj == NULL || pOldObj->IsReferencedExternally() );
//
// since this object was passed in from the outside world, then
// mark it as externally referenced.
//
if ( pObj != NULL )
{
pObj->SetReferencedExternally();
}
g_tlsContext.Set((void*)pObj);
}
void ClearCurrentEssThreadObject()
{
//
// make sure we're not overwriting an existing internal thread object.
// if its externally referenced, we really can't tell if this would
// be a leak or not.
//
CEssThreadObject* pObj = (CEssThreadObject*)g_tlsContext.Get();
_DBG_ASSERT( pObj == NULL || pObj->IsReferencedExternally() );
g_tlsContext.Set(NULL);
}
INTERNAL IWbemContext* GetCurrentEssContext()
{
CEssThreadObject* pThreadObj = (CEssThreadObject*)g_tlsContext.Get();
if(pThreadObj)
return pThreadObj->m_pContext;
else
return NULL;
}
INTERNAL CPostponedList* GetCurrentPostponedList()
{
CEssThreadObject* pThreadObj = (CEssThreadObject*)g_tlsContext.Get();
if(pThreadObj)
return &pThreadObj->m_PostponedList;
else
return NULL;
}
INTERNAL CPostponedList* GetCurrentPostponedEventList()
{
CEssThreadObject* pThreadObj = (CEssThreadObject*)g_tlsContext.Get();
if(pThreadObj)
return &pThreadObj->m_PostponedEventList;
else
return NULL;
}
CEssThreadObject::CEssThreadObject( IWbemContext* pContext )
: m_bReferencedExternally( FALSE )
{
m_pContext = pContext;
if( m_pContext == NULL )
{
m_pContext = GetSpecialContext();
}
if ( m_pContext != NULL )
{
m_pContext->AddRef();
}
}
void CEssThreadObject::SetReferencedExternally()
{
if ( !m_bReferencedExternally )
{
g_lNumExternalThreadObjects++;
m_bReferencedExternally = TRUE;
}
}
IWbemContext* CEssThreadObject::mstatic_pSpecialContext = NULL;
INTERNAL IWbemContext* CEssThreadObject::GetSpecialContext()
{
// Create a "special" context object that will make sure that our
// calls back into CIMOM are not blocked
// ==============================================================
if(mstatic_pSpecialContext == NULL)
{
IWbemCausalityAccess* pCause = NULL;
HRESULT hres = CoCreateInstance(CLSID_WbemContext, NULL,
CLSCTX_INPROC_SERVER, IID_IWbemCausalityAccess,
(void**)&pCause);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Unable to create special context object: "
"0x%X. Danger of deadlock\n", hres));
return NULL;
}
CReleaseMe rm1(pCause);
hres = pCause->MakeSpecial();
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Unable to make the context special: "
"0x%X. Danger of deadlock\n", hres));
return NULL;
}
IWbemContext* pContext = NULL;
hres = pCause->QueryInterface(IID_IWbemContext, (void**)&pContext);
if(FAILED(hres))
{
ERRORTRACE((LOG_ESS, "Internal error: invalid context (0x%X)\n",
hres));
return NULL;
}
if(mstatic_pSpecialContext == NULL) // tiny window for a one-time leak
mstatic_pSpecialContext = pContext;
else
pContext->Release();
}
return mstatic_pSpecialContext;
}
CEssThreadObject::~CEssThreadObject()
{
if ( m_bReferencedExternally )
{
g_lNumExternalThreadObjects--;
//
// since ClearCurrentEssThreadObject() can reference the
// thread object ( for leak checking ) and because we previously
// supported the thread object being deleted before
// CurrentThreadEssThreadObject(), make sure that we perform the
// Clear if the current thread object matches this one. This only
// can happen when the thread object is referenced externally.
//
CEssThreadObject* pObj = (CEssThreadObject*)g_tlsContext.Get();
if ( pObj == this )
{
ClearCurrentEssThreadObject();
}
}
_DBG_ASSERT( m_PostponedList.IsEmpty() );
if ( m_pContext != NULL )
{
m_pContext->Release();
}
}
void /*static*/ CEssThreadObject::ClearSpecialContext()
{
// Call only when no other work can be taking place, e.g. in DllCanUnloadNow
// =========================================================================
if(mstatic_pSpecialContext)
mstatic_pSpecialContext->Release();
mstatic_pSpecialContext = NULL;
}