//****************************************************************************** // // ESSUTILS.CPP // // Copyright (C) 1996-1999 Microsoft Corporation // //****************************************************************************** #include "precomp.h" #include #include "ess.h" #include "essutils.h" #include 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; }