1233 lines
31 KiB
C++
1233 lines
31 KiB
C++
//***************************************************************************
|
|
//
|
|
// WMITASK.CPP
|
|
//
|
|
// raymcc 23-Apr-00 First oversimplified draft for Whistler
|
|
//
|
|
//***************************************************************************
|
|
#include "precomp.h"
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <wbemcore.h>
|
|
#include <wmiarbitrator.h>
|
|
#include <wmifinalizer.h>
|
|
#include <context.h>
|
|
|
|
static ULONG g_uNextTaskId = 1;
|
|
static LONG g_uTaskCount = 0;
|
|
|
|
#ifdef DBG
|
|
#define __DBG_TASK
|
|
#endif
|
|
|
|
extern ULONG g_ulClientCallbackTimeout ;
|
|
|
|
//#define TASK_DETAIL_TRACKING
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
CCritSec CWmiTask::m_TaskCs;
|
|
|
|
CWmiTask* CWmiTask::CreateTask ( )
|
|
{
|
|
return new CWmiTask ( ) ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
CWmiTask::CWmiTask ( )
|
|
{
|
|
m_hResult = WBEM_E_CALL_CANCELLED ;
|
|
m_uRefCount = 1;
|
|
m_uTaskType = 0;
|
|
m_uTaskStatus = 0;
|
|
m_uStartTime = 0;
|
|
m_uUpdateTime = 0;
|
|
m_uTaskId = InterlockedIncrement((LONG *) &g_uNextTaskId);
|
|
InterlockedIncrement((LONG *)&g_uTaskCount);
|
|
m_pUser = 0;
|
|
m_pNs = 0;
|
|
m_pAsyncClientSink = 0;
|
|
m_pWorkingFnz = 0;
|
|
m_pReqSink = 0;
|
|
m_uMemoryUsage = 0;
|
|
m_uTotalSleepTime = 0;
|
|
m_uCancelState = FALSE;
|
|
m_uLastSleepTime = 0;
|
|
m_hTimer = NULL;
|
|
m_pMainCtx = 0;
|
|
m_hCompletion = NULL ;
|
|
m_bReqSinkInitialized = FALSE ;
|
|
m_bAccountedForThrottling = FALSE ;
|
|
m_bCancelledDueToThrottling = FALSE ;
|
|
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWmiTask::~CWmiTask
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
CWmiTask::~CWmiTask()
|
|
{
|
|
int i;
|
|
|
|
CCheckedInCritSec _cs ( &m_csTask );
|
|
|
|
if ( m_pUser )
|
|
{
|
|
_cs.Leave ( ) ;
|
|
m_pUser->Release ( ) ;
|
|
_cs.Enter ( ) ;
|
|
m_pUser = NULL ;
|
|
}
|
|
|
|
if ( m_pNs )
|
|
{
|
|
_cs.Leave ( ) ;
|
|
m_pNs->Release ( ) ;
|
|
_cs.Enter ( ) ;
|
|
m_pNs = NULL ;
|
|
}
|
|
|
|
if ( m_pAsyncClientSink )
|
|
{
|
|
_cs.Leave ( ) ;
|
|
m_pAsyncClientSink->Release ( ) ;
|
|
_cs.Enter ( ) ;
|
|
m_pAsyncClientSink = NULL ;
|
|
}
|
|
|
|
if ( m_pReqSink )
|
|
{
|
|
_cs.Leave ( ) ;
|
|
m_pReqSink->Release ( ) ;
|
|
_cs.Enter ( ) ;
|
|
m_pReqSink = NULL ;
|
|
}
|
|
|
|
if ( m_pMainCtx )
|
|
{
|
|
_cs.Leave ( ) ;
|
|
m_pMainCtx->Release ( ) ;
|
|
_cs.Enter ( ) ;
|
|
m_pMainCtx = NULL ;
|
|
}
|
|
|
|
// Release all provider/sink bindings.
|
|
// ===================================
|
|
|
|
for (i = 0; i < m_aTaskProviders.Size(); i++)
|
|
{
|
|
STaskProvider *pTP = (STaskProvider *) m_aTaskProviders[i];
|
|
if (pTP)
|
|
delete pTP;
|
|
}
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Release all Arbitratees
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
ReleaseArbitratees ( ) ;
|
|
|
|
InterlockedDecrement((LONG *)&g_uTaskCount);
|
|
|
|
if ( m_hTimer )
|
|
{
|
|
CloseHandle ( m_hTimer );
|
|
m_hTimer = NULL ;
|
|
}
|
|
|
|
if ( m_hCompletion )
|
|
{
|
|
CloseHandle ( m_hCompletion ) ;
|
|
m_hCompletion = NULL ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* =============================================================================
|
|
|
|
|
| HRESULT CWmiTask::SignalCancellation ( )
|
|
| ----------------------------------------
|
|
|
|
|
| Signals the task to be cancelled
|
|
|
|
|
|
|
|
* =============================================================================
|
|
*/
|
|
|
|
HRESULT CWmiTask::SignalCancellation ( )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR ;
|
|
|
|
{
|
|
CInCritSec _cs ( &m_csTask );
|
|
|
|
if ( ( m_uTaskStatus != WMICORE_TASK_STATUS_CANCELLED ) && ( m_hTimer != NULL ) )
|
|
{
|
|
SetEvent ( m_hTimer ) ;
|
|
}
|
|
}
|
|
return hRes ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* =============================================================================
|
|
|
|
|
| HRESULT CWmiTask::SetTaskResult ( HRESULT hRes )
|
|
| -------------------------------------------------
|
|
|
|
|
| Sets the task result
|
|
|
|
|
|
|
|
* =============================================================================
|
|
*/
|
|
|
|
HRESULT CWmiTask::SetTaskResult ( HRESULT hResult )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR ;
|
|
|
|
m_hResult = hResult ;
|
|
return hRes ;
|
|
}
|
|
|
|
|
|
/*
|
|
* =============================================================================
|
|
|
|
|
| HRESULT CWmiTask::UpdateMemoryUsage ( LONG lDelta )
|
|
| ---------------------------------------------------
|
|
|
|
|
| Updates the task memory usage
|
|
|
|
|
|
|
|
* =============================================================================
|
|
*/
|
|
|
|
HRESULT CWmiTask::UpdateMemoryUsage ( LONG lDelta )
|
|
{
|
|
CInCritSec _cs ( &m_csTask );
|
|
|
|
m_uMemoryUsage += lDelta ;
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* =============================================================================
|
|
|
|
|
| HRESULT CWmiTask::UpdateTotalSleepTime ( ULONG uSleepTime )
|
|
| -----------------------------------------------------------
|
|
|
|
|
| Updates the tasks sleep time
|
|
|
|
|
|
|
|
* =============================================================================
|
|
*/
|
|
|
|
HRESULT CWmiTask::UpdateTotalSleepTime ( ULONG uSleepTime )
|
|
{
|
|
CInCritSec _cs ( &m_csTask );
|
|
|
|
m_uTotalSleepTime += uSleepTime ;
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* =============================================================================
|
|
|
|
|
| HRESULT CWmiTask::ReleaseArbitratees ( )
|
|
| ----------------------------------------
|
|
|
|
|
| Releases all the arbitratees (Finalizer, Merger currently)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* =============================================================================
|
|
*/
|
|
|
|
HRESULT CWmiTask::ReleaseArbitratees ( )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR ;
|
|
|
|
CInCritSec _cs ( &m_csTask );
|
|
|
|
for (ULONG i = 0; i < m_aArbitratees.Size(); i++)
|
|
{
|
|
_IWmiArbitratee *pArbee = NULL ;
|
|
pArbee = (_IWmiArbitratee*) m_aArbitratees[i];
|
|
if ( pArbee )
|
|
{
|
|
pArbee->Release ( );
|
|
}
|
|
}
|
|
m_aArbitratees.Empty ( ) ;
|
|
|
|
return hRes ;
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
HRESULT CWmiTask::SetRequestSink(CStdSink *pReqSink)
|
|
{
|
|
if (pReqSink == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
if (m_pReqSink != 0)
|
|
return WBEM_E_INVALID_OPERATION;
|
|
|
|
CInCritSec _cs ( &m_csTask );
|
|
pReqSink->AddRef ( ) ;
|
|
m_pReqSink = pReqSink;
|
|
|
|
m_bReqSinkInitialized = TRUE ;
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
// *
|
|
ULONG CWmiTask::AddRef()
|
|
{
|
|
InterlockedIncrement((LONG *) &m_uRefCount);
|
|
return m_uRefCount;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
// *
|
|
ULONG CWmiTask::Release()
|
|
{
|
|
ULONG uNewCount = InterlockedDecrement((LONG *) &m_uRefCount);
|
|
if (0 != uNewCount)
|
|
return uNewCount;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
// *
|
|
HRESULT CWmiTask::QueryInterface(
|
|
IN REFIID riid,
|
|
OUT LPVOID *ppvObj
|
|
)
|
|
{
|
|
*ppvObj = 0;
|
|
|
|
if (IID_IUnknown==riid || IID__IWmiCoreHandle==riid)
|
|
{
|
|
*ppvObj = (_IWmiCoreHandle *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
// *
|
|
HRESULT CWmiTask::GetHandleType(
|
|
ULONG *puType
|
|
)
|
|
{
|
|
*puType = WMI_HANDLE_TASK;
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
// *
|
|
HRESULT CWmiTask::Initialize(
|
|
IN CWbemNamespace *pNs,
|
|
IN ULONG uTaskType,
|
|
IN IWbemContext *pCtx,
|
|
IN IWbemObjectSink *pAsyncClientSinkCopy
|
|
)
|
|
{
|
|
HRESULT hRes;
|
|
|
|
if (pNs == 0 || pCtx == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
m_pNs = pNs;
|
|
m_pNs->AddRef();
|
|
|
|
m_uTaskType = uTaskType;
|
|
m_uStartTime = GetCurrentTime();
|
|
|
|
// See if the task is primary or not.
|
|
// ==================================
|
|
/*
|
|
if (pCtx)
|
|
{
|
|
IWbemCausalityAccess* pCA = NULL;
|
|
pCtx->QueryInterface(IID_IWbemCausalityAccess, (void**)&pCA);
|
|
if (pCA)
|
|
{
|
|
REQUESTID id;
|
|
hRes = pCA->GetParentId(&id);
|
|
if (hRes == S_FALSE)
|
|
m_uTaskType |= WMICORE_TASK_TYPE_PRIMARY;
|
|
else
|
|
m_uTaskType |= WMICORE_TASK_TYPE_DEPENDENT;
|
|
pCA->Release();
|
|
}
|
|
else
|
|
m_uTaskType |= WMICORE_TASK_TYPE_PRIMARY;
|
|
|
|
}
|
|
else
|
|
{
|
|
m_uTaskType |= WMICORE_TASK_TYPE_PRIMARY;
|
|
}
|
|
*/
|
|
if (pCtx)
|
|
{
|
|
CWbemContext *pContext = (CWbemContext *) pCtx;
|
|
|
|
GUID ParentId = GUID_NULL, RequestId = GUID_NULL;
|
|
LONG lNumParents = 0;
|
|
LONG lNumChildren = 0;
|
|
|
|
pContext->GetParentId(&ParentId);
|
|
pContext->GetRequestId(&RequestId);
|
|
pContext->GetHistoryInfo(&lNumParents, &lNumChildren);
|
|
|
|
if (ParentId != GUID_NULL)
|
|
{
|
|
m_uTaskType |= WMICORE_TASK_TYPE_DEPENDENT;
|
|
}
|
|
else
|
|
m_uTaskType |= WMICORE_TASK_TYPE_PRIMARY;
|
|
|
|
m_pMainCtx = (CWbemContext *) pCtx;
|
|
m_pMainCtx->AddRef();
|
|
}
|
|
else
|
|
{
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// If we dont have a context check to see if the namespace is an ESS or Provider
|
|
// initialized namespace, if so, set the task type to dependent.
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
if ( pNs->GetIsESS ( ) || pNs->GetIsProvider ( ) )
|
|
{
|
|
m_uTaskType |= WMICORE_TASK_TYPE_DEPENDENT;
|
|
}
|
|
else
|
|
{
|
|
m_uTaskType |= WMICORE_TASK_TYPE_PRIMARY;
|
|
}
|
|
}
|
|
|
|
|
|
if ((uTaskType & WMICORE_TASK_TYPE_ASYNC) && pAsyncClientSinkCopy)
|
|
{
|
|
m_pAsyncClientSink = pAsyncClientSinkCopy;
|
|
m_pAsyncClientSink->AddRef();
|
|
}
|
|
else
|
|
m_pAsyncClientSink = 0;
|
|
|
|
|
|
// Register this task with Arbitrator.
|
|
// ====================================
|
|
|
|
_IWmiArbitrator *pArb = CWmiArbitrator::GetUnrefedArbitrator();
|
|
if (!pArb)
|
|
return WBEM_E_CRITICAL_ERROR;
|
|
|
|
hRes = pArb->RegisterTask(this);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::SetFinalizer(_IWmiFinalizer *pFnz)
|
|
{
|
|
if (pFnz == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
if (m_pWorkingFnz)
|
|
return WBEM_E_INVALID_OPERATION;
|
|
|
|
m_pWorkingFnz = pFnz;
|
|
m_pWorkingFnz->AddRef();
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::GetFinalizer(_IWmiFinalizer **ppFnz)
|
|
{
|
|
|
|
CInCritSec ics( &m_csTask );
|
|
|
|
for ( int x = 0; x < m_aArbitratees.Size(); x++ )
|
|
{
|
|
_IWmiArbitratee* pArbitratee = (_IWmiArbitratee*) m_aArbitratees[x];
|
|
|
|
if ( SUCCEEDED( pArbitratee->QueryInterface( IID__IWmiFinalizer, (void**) ppFnz ) ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ( x < m_aArbitratees.Size() ? WBEM_S_NO_ERROR : WBEM_E_NOT_FOUND );
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::AddArbitratee( ULONG uFlags, _IWmiArbitratee* pArbitratee )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
if (pArbitratee == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
int nRes = CFlexArray::no_error;
|
|
{
|
|
CInCritSec _cs ( &m_csTask );
|
|
nRes = m_aArbitratees.Add (pArbitratee);
|
|
}
|
|
|
|
if ( nRes != CFlexArray::no_error )
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
pArbitratee->AddRef();
|
|
}
|
|
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::RemoveArbitratee( ULONG uFlags, _IWmiArbitratee* pArbitratee )
|
|
{
|
|
HRESULT hRes = WBEM_E_FAILED;
|
|
|
|
if (pArbitratee == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
CInCritSec _cs ( &m_csTask );
|
|
for (int i = 0; i < m_aArbitratees.Size(); i++)
|
|
{
|
|
_IWmiArbitratee *pArbee = (_IWmiArbitratee*) m_aArbitratees[i];
|
|
|
|
if (pArbee == pArbitratee)
|
|
{
|
|
m_aArbitratees.RemoveAt(i);
|
|
pArbee->Release();
|
|
hRes = WBEM_S_NO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::GetArbitratedQuery( ULONG uFlags, _IWmiArbitratedQuery** ppArbitratedQuery )
|
|
{
|
|
HRESULT hRes = E_NOINTERFACE;
|
|
|
|
if (ppArbitratedQuery == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
{
|
|
CInCritSec _cs ( &m_csTask );
|
|
|
|
for ( int x = 0; FAILED( hRes ) && x < m_aArbitratees.Size(); x++ )
|
|
{
|
|
_IWmiArbitratee* pArb = (_IWmiArbitratee*) m_aArbitratees[x];
|
|
|
|
if ( NULL != pArb )
|
|
{
|
|
hRes = pArb->QueryInterface( IID__IWmiArbitratedQuery, (void**) ppArbitratedQuery );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
HRESULT CWmiTask::GetPrimaryTask ( _IWmiCoreHandle** pPTask )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
if ( pPTask == NULL )
|
|
{
|
|
hRes = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
*pPTask = (_IWmiCoreHandle*) this;
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::Cancel( HRESULT hResParam )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
BOOL bCancelled = FALSE ;
|
|
|
|
// We'll want one of these in order to track statuses from all plausible locations if
|
|
// we are performing a client originated cancel
|
|
CStatusSink* pStatusSink = NULL;
|
|
|
|
if ( hResParam == WMIARB_CALL_CANCELLED_CLIENT )
|
|
{
|
|
pStatusSink = new CStatusSink;
|
|
|
|
if ( NULL == pStatusSink )
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
} // IF Client originated the call
|
|
|
|
// Auto Release
|
|
CReleaseMe rmStatusSink( pStatusSink );
|
|
|
|
{
|
|
CCheckedInCritSec _cs ( &m_csTask );
|
|
if (m_uTaskStatus == WMICORE_TASK_STATUS_CANCELLED)
|
|
{
|
|
return WBEM_S_NO_ERROR; // Prevent reentrancy
|
|
}
|
|
m_uTaskStatus = WMICORE_TASK_STATUS_CANCELLED;
|
|
}
|
|
|
|
// Change this to an async scheduled request
|
|
// ==========================================
|
|
|
|
if (CORE_TASK_TYPE(m_uTaskType) == WMICORE_TASK_EXEC_NOTIFICATION_QUERY)
|
|
{
|
|
CAsyncReq_RemoveNotifySink *pReq = new
|
|
CAsyncReq_RemoveNotifySink(m_pReqSink, pStatusSink);
|
|
if (!pReq)
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else if ( NULL != pReq->GetContext() )
|
|
{
|
|
|
|
pReq->SetForceRun ( 1 ) ;
|
|
|
|
// If we have a status sink, then we should wait until the operation
|
|
// completes before continuing so we can get the proper status from the
|
|
// sink.
|
|
if ( NULL != pStatusSink )
|
|
{
|
|
hRes = ConfigMgr::EnqueueRequestAndWait(pReq);
|
|
}
|
|
else
|
|
{
|
|
hRes = ConfigMgr::EnqueueRequest(pReq);
|
|
}
|
|
bCancelled = TRUE ;
|
|
|
|
} // ELSEIF NULL != pReq->GetContext()
|
|
else
|
|
{
|
|
delete pReq;
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// If here, a normal task. Loop through any providers and stop them.
|
|
// ==================================================================
|
|
CFlexArray aTempProviders;
|
|
|
|
// This could change while we're accessing, so do this in a critsec
|
|
{
|
|
CInCritSec ics( &m_csTask );
|
|
|
|
for (int i = 0; SUCCEEDED( hRes ) && i < m_aTaskProviders.Size(); i++)
|
|
{
|
|
if ( aTempProviders.Add( m_aTaskProviders[i] ) != CFlexArray::no_error )
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
} // FOR i= 0;
|
|
|
|
} // SCOPED critsec
|
|
|
|
// Cancel what we've got
|
|
for (int i = 0; i < aTempProviders.Size(); i++)
|
|
{
|
|
STaskProvider *pTP = (STaskProvider *) aTempProviders[i];
|
|
if (pTP)
|
|
{
|
|
pTP->Cancel( pStatusSink );
|
|
}
|
|
}
|
|
|
|
|
|
CStdSink* pTempSink = NULL;
|
|
{
|
|
CInCritSec _cs ( &m_csTask );
|
|
if (m_pReqSink)
|
|
{
|
|
pTempSink = m_pReqSink;
|
|
pTempSink->AddRef ( );
|
|
m_pReqSink->Release ( );
|
|
m_pReqSink = 0;
|
|
}
|
|
}
|
|
|
|
if ( pTempSink )
|
|
{
|
|
pTempSink->Cancel();
|
|
pTempSink->Release();
|
|
}
|
|
|
|
//
|
|
// Loop through all arbitratees and set the operation result to cancelled
|
|
//
|
|
if ( SUCCEEDED ( hRes ) )
|
|
{
|
|
if ( bCancelled == FALSE )
|
|
{
|
|
if ( !m_hCompletion && hResParam == WMIARB_CALL_CANCELLED_CLIENT )
|
|
{
|
|
m_hCompletion = CreateEvent ( NULL, TRUE, FALSE, NULL ) ;
|
|
if ( m_hCompletion == NULL )
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY ;
|
|
}
|
|
}
|
|
|
|
_IWmiFinalizer* pFinalizer = NULL ;
|
|
if ( SUCCEEDED ( hRes ) )
|
|
{
|
|
if ( m_hCompletion && hResParam == WMIARB_CALL_CANCELLED_CLIENT )
|
|
{
|
|
//
|
|
// We need the finalizer to set the client wakeup event
|
|
//
|
|
hRes = GetFinalizer ( &pFinalizer ) ;
|
|
if ( FAILED (hRes) )
|
|
{
|
|
hRes = WBEM_E_FAILED ;
|
|
}
|
|
else
|
|
{
|
|
((CWmiFinalizer*)pFinalizer)->SetClientCancellationHandle ( m_hCompletion ) ;
|
|
}
|
|
}
|
|
}
|
|
CReleaseMe FinalizerRelease ( pFinalizer ) ;
|
|
|
|
//
|
|
// only enter wait state if we successfully created and set the client wait event
|
|
//
|
|
if ( SUCCEEDED ( hRes ) )
|
|
{
|
|
if ( hResParam == WMIARB_CALL_CANCELLED_CLIENT || hResParam == WMIARB_CALL_CANCELLED_THROTTLING )
|
|
{
|
|
hRes = SetArbitrateesOperationResult ( 0, WBEM_E_CALL_CANCELLED_CLIENT ) ;
|
|
}
|
|
else
|
|
{
|
|
hRes = SetArbitrateesOperationResult ( 0, m_hResult ) ;
|
|
}
|
|
|
|
if ( m_hCompletion && hResParam == WMIARB_CALL_CANCELLED_CLIENT )
|
|
{
|
|
if ( ((CWmiFinalizer*)pFinalizer)->IsValidDestinationSink ( ) )
|
|
{
|
|
DWORD dwRet = CCoreQueue::QueueWaitForSingleObject ( m_hCompletion, g_ulClientCallbackTimeout ) ;
|
|
if (dwRet == WAIT_TIMEOUT)
|
|
{
|
|
hRes = WBEM_S_TIMEDOUT ;
|
|
}
|
|
}
|
|
|
|
((CWmiFinalizer*)pFinalizer)->CancelWaitHandle ( ) ;
|
|
|
|
if ( m_hCompletion )
|
|
{
|
|
CloseHandle ( m_hCompletion ) ;
|
|
m_hCompletion = NULL ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We're done, get the final status from the status sink if we have one.
|
|
//
|
|
if ( NULL != pStatusSink )
|
|
{
|
|
hRes = pStatusSink->GetLastStatus();
|
|
}
|
|
|
|
ReleaseArbitratees ( ) ;
|
|
return hRes ;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
STaskProvider::~STaskProvider()
|
|
{
|
|
if (m_pProvSink)
|
|
m_pProvSink->LocalRelease();
|
|
ReleaseIfNotNULL(m_pProv);
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT STaskProvider::Cancel( CStatusSink* pStatusSink )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR ;
|
|
IWbemServices *pTmpProv = 0;
|
|
CProviderSink *pTmpProvSink = 0;
|
|
|
|
EnterCriticalSection(&CWmiTask::m_TaskCs);
|
|
if (m_pProv != 0)
|
|
{
|
|
pTmpProv = m_pProv;
|
|
m_pProv = 0;
|
|
}
|
|
if (m_pProvSink != 0)
|
|
{
|
|
pTmpProvSink = m_pProvSink;
|
|
m_pProvSink = 0;
|
|
}
|
|
LeaveCriticalSection(&CWmiTask::m_TaskCs);
|
|
|
|
if (pTmpProvSink)
|
|
{
|
|
pTmpProvSink->Cancel();
|
|
}
|
|
|
|
if (pTmpProv)
|
|
{
|
|
hRes = ExecCancelOnNewRequest ( pTmpProv, pTmpProvSink, pStatusSink ) ;
|
|
}
|
|
|
|
ReleaseIfNotNULL(pTmpProv);
|
|
ReleaseIfNotNULL(pTmpProvSink);
|
|
|
|
return hRes ;
|
|
}
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Used when issuing CancelAsyncCall to providers associtated with the task.
|
|
// Rather than calling CancelAsynCall directly on the provider, we create a brand
|
|
// new request and execute it on a different thread. We do this to avoid hangs, since
|
|
// PSS is waiting the Indicate/SetStatus call to return before servicing the CancelCallAsync.
|
|
//
|
|
// //////////////////////////////////////////////////////////////////////////////////////////
|
|
HRESULT STaskProvider::ExecCancelOnNewRequest ( IWbemServices* pProv, CProviderSink* pSink, CStatusSink* pStatusSink )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR ;
|
|
|
|
//
|
|
// Sanity check on params
|
|
//
|
|
if ( pSink == NULL )
|
|
{
|
|
hRes = WBEM_E_INVALID_PARAMETER ;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create new request
|
|
//
|
|
CAsyncReq_CancelProvAsyncCall* pReq = new CAsyncReq_CancelProvAsyncCall ( pProv, pSink, pStatusSink ) ;
|
|
|
|
if ( pReq == NULL )
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY ;
|
|
}
|
|
else if ( NULL != pReq->GetContext() )
|
|
{
|
|
pReq->SetForceRun ( 1 ) ;
|
|
//
|
|
// Enqueue the request
|
|
//
|
|
|
|
// If we have a status sink, then we should wait until the operation
|
|
// completes before continuing so we can get the proper status from the
|
|
// sink.
|
|
if ( NULL != pStatusSink )
|
|
{
|
|
hRes = ConfigMgr::EnqueueRequestAndWait(pReq);
|
|
}
|
|
else
|
|
{
|
|
hRes = ConfigMgr::EnqueueRequest(pReq);
|
|
}
|
|
|
|
if ( FAILED ( hRes ) )
|
|
{
|
|
delete pReq ;
|
|
}
|
|
} // ELSEIF pReq->GetContext() == NULL
|
|
else
|
|
{
|
|
delete pReq;
|
|
hRes = WBEM_E_OUT_OF_MEMORY ;
|
|
}
|
|
}
|
|
return hRes ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
BOOL CWmiTask::IsESSNamespace ( )
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if ( m_pNs )
|
|
{
|
|
bRet = m_pNs->GetIsESS ( );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
BOOL CWmiTask::IsProviderNamespace ( )
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if ( m_pNs )
|
|
{
|
|
bRet = m_pNs->GetIsProvider ( );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::AddTaskProv(STaskProvider *p)
|
|
{
|
|
CInCritSec ics( &m_csTask );
|
|
|
|
// There is a race condition in which the task could get cancelled just as we
|
|
// are executing. In this case, the task status will indicate that it has been
|
|
// cancelled, so we should not add it to the task providers list.
|
|
|
|
if (m_uTaskStatus == WMICORE_TASK_STATUS_CANCELLED)
|
|
return WBEM_E_CALL_CANCELLED; // Prevent reentrancy
|
|
|
|
int nRes = m_aTaskProviders.Add(p);
|
|
if (nRes)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::HasMatchingSink(void *Test, IN REFIID riid)
|
|
{
|
|
if (LPVOID(m_pAsyncClientSink) == LPVOID(Test))
|
|
return WBEM_S_NO_ERROR;
|
|
return WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::CreateTimerEvent ( )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
{
|
|
CCheckedInCritSec _cs ( &m_csTask );
|
|
if ( !m_hTimer )
|
|
{
|
|
m_hTimer = CreateEvent ( NULL, TRUE, FALSE, NULL );
|
|
if ( !m_hTimer )
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
HRESULT CWmiTask::SetArbitrateesOperationResult ( ULONG lFlags, HRESULT hResult )
|
|
{
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Set the operation result of all Arbitratees
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
CFlexArray aTmp;
|
|
{
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// First grab all the arbitratees and stick them into
|
|
// a temp array
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
CInCritSec _cs ( &m_csTask );
|
|
for (int i = 0; i < m_aArbitratees.Size(); i++)
|
|
{
|
|
_IWmiArbitratee *pArbee = (_IWmiArbitratee*) m_aArbitratees[i];
|
|
|
|
if ( pArbee )
|
|
{
|
|
int nRes = aTmp.Add (pArbee);
|
|
if ( nRes != CFlexArray::no_error )
|
|
{
|
|
hRes = WBEM_E_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
pArbee->AddRef ( );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( SUCCEEDED (hRes) )
|
|
{
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Clear to set the operation result without problems
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
for (int i = 0; i < aTmp.Size(); i++)
|
|
{
|
|
_IWmiArbitratee *pArbee = (_IWmiArbitratee*) aTmp[i];
|
|
if ( pArbee )
|
|
{
|
|
pArbee->SetOperationResult(lFlags, hResult );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Now clean everything up
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
for (int i = 0; i < aTmp.Size(); i++)
|
|
{
|
|
_IWmiArbitratee *pArbee = (_IWmiArbitratee*) aTmp[i];
|
|
if ( pArbee )
|
|
{
|
|
pArbee->Release ( );
|
|
}
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
HRESULT CWmiTask::Dump(FILE* f)
|
|
{
|
|
fprintf(f, "---Task = 0x%p----------------------------\n", this);
|
|
fprintf(f, " Refcount = %d\n", m_uRefCount);
|
|
fprintf(f, " TaskStatus = %u\n ", m_uTaskStatus);
|
|
fprintf(f, " Task ID = %u\n", m_uTaskId);
|
|
|
|
// Task status
|
|
char *p = "<none>";
|
|
switch(m_uTaskStatus)
|
|
{
|
|
case WMICORE_TASK_STATUS_NEW: p = "WMICORE_TASK_STATUS_NEW"; break;
|
|
case WMICORE_TASK_STATUS_VALIDATED: p = "WMICORE_TASK_STATUS_VALIDATED"; break;
|
|
case WMICORE_TASK_STATUS_SUSPENDED: p = "WMICORE_TASK_STATUS_SUSPENDED"; break;
|
|
case WMICORE_TASK_STATUS_EXECUTING: p = "WMICORE_TASK_STATUS_EXECUTING"; break;
|
|
case WMICORE_TASK_STATUS_WAITING_ON_SUBTASKS: p = "WMICORE_TASK_STATUS_WAITING_ON_SUBTASKS"; break;
|
|
case WMICORE_TASK_STATUS_TIMED_OUT: p = "WMICORE_TASK_STATUS_TIMED_OUT"; break;
|
|
case WMICORE_TASK_STATUS_CORE_COMPLETED: p = "WMICORE_TASK_STATUS_CORE_COMPLETED"; break;
|
|
case WMICORE_TASK_STATUS_CLIENT_COMPLETED: p = "WMICORE_TASK_STATUS_CLIENT_COMPLETED"; break;
|
|
case WMICORE_TASK_STATUS_CANCELLED: p = "WMICORE_TASK_STATUS_CANCELLED"; break;
|
|
case WMICORE_TASK_STATUS_FAILED: p = "WMICORE_TASK_STATUS_FAILED"; break;
|
|
};
|
|
|
|
fprintf(f, " %s\n", p);
|
|
|
|
// Task type
|
|
p = "<none>";
|
|
switch(m_uTaskType & 0xFF)
|
|
{
|
|
case WMICORE_TASK_NULL: p = "WMICORE_TASK_NULL"; break;
|
|
case WMICORE_TASK_GET_OBJECT: p = "WMICORE_TASK_GET_OBJECT"; break;
|
|
case WMICORE_TASK_GET_INSTANCE: p = "WMICORE_TASK_GET_INSTANCE"; break;
|
|
case WMICORE_TASK_PUT_INSTANCE: p = "WMICORE_TASK_PUT_INSTANCE"; break;
|
|
case WMICORE_TASK_DELETE_INSTANCE: p = "WMICORE_TASK_DELETE_INSTANCE"; break;
|
|
case WMICORE_TASK_ENUM_INSTANCES: p = "WMICORE_TASK_ENUM_INSTANCES"; break;
|
|
case WMICORE_TASK_GET_CLASS: p = "WMICORE_TASK_GET_CLASS"; break;
|
|
case WMICORE_TASK_PUT_CLASS: p = "WMICORE_TASK_PUT_CLASS"; break;
|
|
case WMICORE_TASK_DELETE_CLASS: p = "WMICORE_TASK_DELETE_CLASS"; break;
|
|
case WMICORE_TASK_ENUM_CLASSES: p = "WMICORE_TASK_ENUM_CLASSES"; break;
|
|
case WMICORE_TASK_EXEC_QUERY: p = "WMICORE_TASK_EXEC_QUERY"; break;
|
|
case WMICORE_TASK_EXEC_METHOD: p = "WMICORE_TASK_EXEC_METHOD"; break;
|
|
case WMICORE_TASK_OPEN: p = "WMICORE_TASK_OPEN"; break;
|
|
case WMICORE_TASK_OPEN_SCOPE: p = "WMICORE_TASK_OPEN_SCOPE"; break;
|
|
case WMICORE_TASK_OPEN_NAMESPACE: p = "WMICORE_TASK_OPEN_NAMESPACE"; break;
|
|
case WMICORE_TASK_EXEC_NOTIFICATION_QUERY: p = "WMICORE_TASK_EXEC_NOTIFICATION_QUERY"; break;
|
|
}
|
|
|
|
fprintf(f, " TaskType = [0x%X] %s ", m_uTaskType, p);
|
|
|
|
if (m_uTaskType & WMICORE_TASK_TYPE_SYNC)
|
|
fprintf(f, " WMICORE_TASK_TYPE_SYNC");
|
|
|
|
if (m_uTaskType & WMICORE_TASK_TYPE_SEMISYNC)
|
|
fprintf(f, " WMICORE_TASK_TYPE_SEMISYNC");
|
|
|
|
if (m_uTaskType & WMICORE_TASK_TYPE_ASYNC)
|
|
fprintf(f, " WMICORE_TASK_TYPE_ASYNC");
|
|
|
|
if (m_uTaskType & WMICORE_TASK_TYPE_PRIMARY)
|
|
fprintf(f, " WMICORE_TASK_TYPE_PRIMARY");
|
|
|
|
if (m_uTaskType & WMICORE_TASK_TYPE_DEPENDENT)
|
|
fprintf(f, " WMICORE_TASK_TYPE_DEPENDENT");
|
|
|
|
fprintf(f, "\n");
|
|
|
|
fprintf(f, " Task Log Info = %S\n", LPWSTR(m_sDebugInfo));
|
|
fprintf(f, " AsyncClientSink = 0x%p\n", m_pAsyncClientSink);
|
|
fprintf(f, " Finalizer = 0x%p\n", m_pWorkingFnz);
|
|
|
|
CCheckedInCritSec ics( &m_csTask );
|
|
|
|
for (int i = 0; i < m_aTaskProviders.Size(); i++)
|
|
{
|
|
STaskProvider *pTP = (STaskProvider *) m_aTaskProviders[i];
|
|
fprintf(f, " Task Provider [0x%p] Prov=0x%p Sink=0x%p\n", this, pTP->m_pProv, pTP->m_pProvSink);
|
|
}
|
|
|
|
ics.Leave();
|
|
|
|
DWORD dwAge = GetCurrentTime() - m_uStartTime;
|
|
|
|
fprintf(f, " CWbemNamespace = 0x%p\n", m_pNs);
|
|
fprintf(f, " Task age = %d milliseconds\n", dwAge);
|
|
fprintf(f, " Task last sleep time = %d ms\n", m_uLastSleepTime );
|
|
|
|
fprintf(f, "\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
int __cdecl CWmiTask::printf(const char *fmt, ...)
|
|
{
|
|
#ifdef TASK_DETAIL_TRACKING
|
|
static CRITICAL_SECTION csPrintf;
|
|
static BOOL bInit = FALSE;
|
|
|
|
if (bInit == FALSE)
|
|
{
|
|
InitializeCriticalSection(&csPrintf);
|
|
bInit = TRUE;
|
|
}
|
|
|
|
const int nBufSize = 0x8000;
|
|
static LONG Protect = -1;
|
|
char buffer[nBufSize];
|
|
|
|
va_list argptr;
|
|
int cnt;
|
|
va_start(argptr, fmt);
|
|
cnt = _vsnprintf(buffer, nBufSize, fmt, argptr);
|
|
if (cnt == -1)
|
|
buffer[nBufSize] = 0; // Null terminate manually; see _vsnprintf spec
|
|
va_end(argptr);
|
|
|
|
EnterCriticalSection(&csPrintf);
|
|
m_sDebugInfo += buffer;
|
|
LeaveCriticalSection(&csPrintf);
|
|
|
|
return cnt;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
*/
|
|
|