227 lines
6.1 KiB
C++
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;
|
||
|
}
|
||
|
|
||
|
|