713 lines
17 KiB
C++
713 lines
17 KiB
C++
/*++
|
|
|
|
Copyright (C) 1997-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
RQUEUE.CPP
|
|
|
|
Abstract:
|
|
|
|
Declarations for CRequestQueue, which to keep track of calls
|
|
which have not yet been answered.
|
|
|
|
History:
|
|
|
|
a-davj 15-Aug-96 Created.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "wmishared.h"
|
|
|
|
// This macro used used ensure that the request queue is valid and to
|
|
// get the MUTEX for accessing the request array.
|
|
|
|
#define GETMUTEX(mutex, badres) \
|
|
if(mutex == NULL || m_RequestContainer == NULL) \
|
|
return badres; \
|
|
dwRet = WbemWaitForSingleObject(mutex,MAX_WAIT_FOR_WRITE); \
|
|
if(dwRet != WAIT_OBJECT_0) \
|
|
return badres;
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CRequestQueue::CRequestQueue
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Constructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CRequestQueue :: CRequestQueue () : m_RequestContainer ( NULL ) , m_RequestContainerSize ( 0 )
|
|
{
|
|
m_Mutex = CreateMutex ( NULL , FALSE , NULL ) ;
|
|
|
|
InitializeCriticalSection(&m_cs);
|
|
|
|
int t_FreeSlotIndex ;
|
|
|
|
if ( ! ExpandArray ( INITIAL_QUEUE_SIZE , t_FreeSlotIndex ) )
|
|
{
|
|
FreeStuff () ;
|
|
}
|
|
|
|
ObjectCreated(OBJECT_TYPE_RQUEUE) ;
|
|
}
|
|
//***************************************************************************
|
|
//
|
|
// CRequestQueue::~CRequestQueue
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
CRequestQueue :: ~CRequestQueue ()
|
|
{
|
|
FreeStuff () ;
|
|
ObjectDestroyed(OBJECT_TYPE_RQUEUE) ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// void CRequestQueue::FreeStuff
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Frees up resources. Generally used by destructor.
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CRequestQueue::FreeStuff()
|
|
{
|
|
DWORD dwCnt;
|
|
for ( dwCnt = 0 ; dwCnt < m_RequestContainerSize && m_RequestContainer ; dwCnt ++ )
|
|
{
|
|
if ( m_RequestContainer [ dwCnt ].m_Event )
|
|
{
|
|
CloseHandle ( m_RequestContainer [ dwCnt ].m_Event ) ;
|
|
}
|
|
}
|
|
|
|
if ( m_Mutex )
|
|
CloseHandle ( m_Mutex ) ;
|
|
|
|
DeleteCriticalSection(&m_cs);
|
|
|
|
if ( m_RequestContainer )
|
|
delete [] m_RequestContainer ;
|
|
|
|
m_Mutex = NULL ;
|
|
m_RequestContainer = NULL ;
|
|
m_RequestContainerSize = 0 ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// DWORD CRequestQueue::dwStatus
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Gets the status.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// Status, no_error if ok.
|
|
//***************************************************************************
|
|
|
|
DWORD CRequestQueue :: GetStatus ()
|
|
{
|
|
return ( m_Mutex && m_RequestContainer ) ? CComLink::no_error : CComLink::failed ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// int CRequestQueue::iGetEmptySlot
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Finds an empty slot to be used. Will expand the array if
|
|
// necessary.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// index of empty slot, -1 if error.
|
|
//
|
|
//***************************************************************************
|
|
|
|
int CRequestQueue :: GetEmptySlot ()
|
|
{
|
|
int iCnt ;
|
|
|
|
// find an empty slot in the requests list
|
|
|
|
for ( iCnt = 0 ; (DWORD)iCnt < m_RequestContainerSize ; iCnt ++ )
|
|
{
|
|
if ( m_RequestContainer [ iCnt ].m_InUse == FALSE && m_RequestContainer [ iCnt ].m_Event != NULL )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if there was no empty slot, expand the array
|
|
|
|
if ( (DWORD) iCnt == m_RequestContainerSize )
|
|
{
|
|
if ( ! ExpandArray ( INITIAL_QUEUE_SIZE , iCnt ) )
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return iCnt ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// BOOL CRequestQueue :: FindByRequestId
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Finds a entry by the guid.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// guidToFind what to look for
|
|
// pdwEntry set to index
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// TRUE if found.
|
|
//
|
|
//***************************************************************************
|
|
|
|
BOOL CRequestQueue :: FindByRequestId (
|
|
|
|
RequestId a_RequestId ,
|
|
DWORD &pdwEntry
|
|
)
|
|
{
|
|
DWORD dwCnt ;
|
|
|
|
for ( dwCnt = 0 ; dwCnt < m_RequestContainerSize ; dwCnt ++ )
|
|
{
|
|
if ( m_RequestContainer [ dwCnt ].m_RequestId == a_RequestId && m_RequestContainer [ dwCnt ].m_InUse )
|
|
{
|
|
pdwEntry = dwCnt ;
|
|
return TRUE ;
|
|
}
|
|
}
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// BOOL CRequestQueue :: FindByHandle
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Finds a entry by the event handle.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hEventToFind what to look for
|
|
// pdwEntry set to index
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// TRUE if found.
|
|
//
|
|
//***************************************************************************
|
|
|
|
BOOL CRequestQueue :: FindByHandle (
|
|
|
|
HANDLE hEventToFind,
|
|
DWORD &pdwEntry
|
|
)
|
|
{
|
|
DWORD dwCnt;
|
|
|
|
for ( dwCnt = 0 ; dwCnt < m_RequestContainerSize ; dwCnt ++ )
|
|
{
|
|
if ( m_RequestContainer [ dwCnt ].m_Event == hEventToFind && m_RequestContainer [ dwCnt ].m_InUse )
|
|
{
|
|
pdwEntry = dwCnt ;
|
|
return TRUE ;
|
|
}
|
|
}
|
|
|
|
return FALSE ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HANDLE CRequestQueue::BeginPacket
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called at the start of a write. Get a slot, generate a new guid
|
|
// and store the read stream that will be used to store the returned value.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pRead pointer to stream where results are to be stored.
|
|
// pguidID set to guid to identify the packet.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// handle to event that can be set when something happens.
|
|
// NULL if error.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HANDLE CRequestQueue::AllocateRequest (
|
|
|
|
IN IOperation &a_Operation
|
|
)
|
|
{
|
|
HANDLE hRet = NULL ;
|
|
|
|
#if 0
|
|
GETMUTEX(m_Mutex, NULL)
|
|
#else
|
|
EnterCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
int iUse = GetEmptySlot () ;
|
|
if ( iUse != -1 )
|
|
{
|
|
m_RequestContainer [ iUse ].m_InUse = TRUE;
|
|
m_RequestContainer [ iUse ].m_Operation = & a_Operation ;
|
|
m_RequestContainer [ iUse ].m_RequestId = a_Operation.GetRequestId () ;
|
|
m_RequestContainer [ iUse ].m_Status = NO_REPLY_YET;
|
|
|
|
// The slots event handle is also to be returned. This event will
|
|
// be signaled by the read thread when the reply comes, but for now
|
|
// reset it .
|
|
// ================================================================
|
|
|
|
hRet = m_RequestContainer [ iUse ].m_Event ;
|
|
ResetEvent ( hRet ) ;
|
|
}
|
|
|
|
#if 0
|
|
ReleaseMutex ( m_Mutex ) ;
|
|
#else
|
|
LeaveCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
return hRet ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HANDLE CRequestQueue::BeginPacket
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called at the start of a write. Get a slot, generate a new guid
|
|
// and store the read stream that will be used to store the returned value.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// pRead pointer to stream where results are to be stored.
|
|
// pguidID set to guid to identify the packet.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// handle to event that can be set when something happens.
|
|
// NULL if error.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HANDLE CRequestQueue::UnLockedAllocateRequest (
|
|
|
|
IN IOperation &a_Operation
|
|
)
|
|
{
|
|
HANDLE hRet = NULL ;
|
|
|
|
int iUse = GetEmptySlot () ;
|
|
if ( iUse != -1 )
|
|
{
|
|
m_RequestContainer [ iUse ].m_InUse = TRUE;
|
|
m_RequestContainer [ iUse ].m_Operation = & a_Operation ;
|
|
m_RequestContainer [ iUse ].m_RequestId = a_Operation.GetRequestId () ;
|
|
m_RequestContainer [ iUse ].m_Status = NO_REPLY_YET;
|
|
|
|
// The slots event handle is also to be returned. This event will
|
|
// be signaled by the read thread when the reply comes, but for now
|
|
// reset it .
|
|
// ================================================================
|
|
|
|
hRet = m_RequestContainer [ iUse ].m_Event ;
|
|
ResetEvent ( hRet ) ;
|
|
}
|
|
|
|
return hRet ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// DWORD CRequestQueue::GetLastMsg
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called to get the response to a written packet. Typically used
|
|
// when determining what the result was of sending a message.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hEvent handle used to find the request
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// Last message received. See COMLINK.H for a list of the messages.
|
|
// WBEM_E_FAILED is set if there is no last message.
|
|
//
|
|
//***************************************************************************
|
|
|
|
DWORD CRequestQueue :: GetRequestStatus ( IN HANDLE a_Event )
|
|
{
|
|
DWORD dwRet = WBEM_E_FAILED ; // Set later on
|
|
|
|
#if 0
|
|
GETMUTEX(m_Mutex, WBEM_E_FAILED)
|
|
#else
|
|
EnterCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
// find a packet in the list
|
|
|
|
DWORD dwCnt;
|
|
if ( FindByHandle ( a_Event , dwCnt ) )
|
|
dwRet = m_RequestContainer [ dwCnt ].m_Status ;
|
|
|
|
#if 0
|
|
ReleaseMutex ( m_Mutex ) ;
|
|
#else
|
|
LeaveCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
return dwRet ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// DWORD CRequestQueue::DeallocateRequest
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called when packet is done and the caller is through with the
|
|
// slot.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hEvent handle used to find the request
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// WBEM_E_FAILED if error, otherwise last response value
|
|
//
|
|
//***************************************************************************
|
|
|
|
DWORD CRequestQueue :: DeallocateRequest ( IN HANDLE a_Event )
|
|
{
|
|
DWORD dwRet = WBEM_E_FAILED ; // Set later on
|
|
|
|
#if 0
|
|
GETMUTEX(m_Mutex , WBEM_E_FAILED)
|
|
#else
|
|
EnterCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
// find a packet in the list
|
|
|
|
DWORD dwCnt ;
|
|
if ( FindByHandle ( a_Event , dwCnt ) )
|
|
{
|
|
m_RequestContainer [ dwCnt ].m_InUse = FALSE ;
|
|
dwRet = m_RequestContainer [ dwCnt ].m_Status ;
|
|
}
|
|
|
|
#if 0
|
|
ReleaseMutex ( m_Mutex ) ;
|
|
#else
|
|
LeaveCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
return dwRet ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// DWORD CRequestQueue::DeallocateRequest
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called when packet is done and the caller is through with the
|
|
// slot.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hEvent handle used to find the request
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// WBEM_E_FAILED if error, otherwise last response value
|
|
//
|
|
//***************************************************************************
|
|
|
|
DWORD CRequestQueue :: UnLockedDeallocateRequest ( IN HANDLE a_Event )
|
|
{
|
|
DWORD dwRet = WBEM_E_FAILED ; // Set later on
|
|
|
|
// find a packet in the list
|
|
|
|
DWORD dwCnt ;
|
|
if ( FindByHandle ( a_Event , dwCnt ) )
|
|
{
|
|
m_RequestContainer [ dwCnt ].m_InUse = FALSE ;
|
|
dwRet = m_RequestContainer [ dwCnt ].m_Status ;
|
|
}
|
|
|
|
return dwRet ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CMemStream * CRequestQueue::GetStream
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called by a read thread when a response comes back.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// guidPacketID guid used to find the request
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// The memory stream that is to be used for the reply, NULL if
|
|
// error.
|
|
//
|
|
//***************************************************************************
|
|
|
|
IOperation *CRequestQueue :: GetOperation ( RequestId a_RequestId )
|
|
{
|
|
IOperation *t_Operation = NULL ;
|
|
|
|
#if 0
|
|
GETMUTEX(m_Mutex, NULL)
|
|
#else
|
|
EnterCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
|
|
// find an packet in the list
|
|
|
|
DWORD dwCnt ;
|
|
if ( FindByRequestId ( a_RequestId , dwCnt ) )
|
|
t_Operation = m_RequestContainer [ dwCnt ].m_Operation ;
|
|
|
|
#if 0
|
|
ReleaseMutex ( m_Mutex ) ;
|
|
#else
|
|
LeaveCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
return t_Operation ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HANDLE CRequestQueue::SetEventAndType
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called by the read thread in order to set the return code
|
|
// of the call.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// guidPacketID guid used to find the request
|
|
// dwType result
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// Handle of event, NULL if the packetID is invalid.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HANDLE CRequestQueue :: SetEventAndStatus (
|
|
|
|
RequestId a_RequestId ,
|
|
IN DWORD a_Status
|
|
)
|
|
{
|
|
HANDLE t_Handle = NULL;
|
|
|
|
#if 0
|
|
GETMUTEX(m_Mutex, NULL)
|
|
#else
|
|
EnterCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
// find an packet in the list
|
|
|
|
DWORD dwCnt;
|
|
if( FindByRequestId ( a_RequestId , dwCnt ) )
|
|
{
|
|
t_Handle = m_RequestContainer [ dwCnt ].m_Event ;
|
|
m_RequestContainer[dwCnt].m_Status = a_Status ;
|
|
|
|
SetEvent ( t_Handle ) ;
|
|
}
|
|
|
|
#if 0
|
|
ReleaseMutex ( m_Mutex ) ;
|
|
#else
|
|
LeaveCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
return t_Handle ;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// HANDLE CRequestQueue::GetHandle
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// gets the event handle.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// guidPacketID guid used to find the request
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// event handle, NULL if the packetID is invalid.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HANDLE CRequestQueue :: GetHandle ( RequestId a_RequestId )
|
|
{
|
|
HANDLE t_Handle = NULL ;
|
|
|
|
#if 0
|
|
GETMUTEX(m_Mutex, NULL)
|
|
#else
|
|
EnterCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
// find an packet in the list
|
|
|
|
DWORD dwCnt;
|
|
if ( FindByRequestId ( a_RequestId , dwCnt ) )
|
|
t_Handle = m_RequestContainer [ dwCnt ].m_Event ;
|
|
|
|
#if 0
|
|
ReleaseMutex ( m_Mutex ) ;
|
|
#else
|
|
LeaveCriticalSection(&m_cs);
|
|
#endif
|
|
|
|
return t_Handle ;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// BOOL CRequestQueue :: ExpandArray
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Expands the number of slots that can be used to hold call data.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// dwAdditionalEntries number to add
|
|
// piAvailable set to available slots
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// TRUE if OK.
|
|
//
|
|
//***************************************************************************
|
|
|
|
BOOL CRequestQueue :: ExpandArray (
|
|
|
|
IN DWORD dwAdditionalEntries ,
|
|
OUT int &piAvailable
|
|
)
|
|
{
|
|
BOOL bOK = FALSE ;
|
|
|
|
// Allocate an array big enough for any existing entries and
|
|
// the new entries.
|
|
// =========================================================
|
|
|
|
DWORD dwAllocSize = dwAdditionalEntries + m_RequestContainerSize ;
|
|
Request *pNewRequests = new Request [ dwAllocSize ] ;
|
|
|
|
if ( pNewRequests == NULL )
|
|
return FALSE ;
|
|
|
|
// For array elements that already exist, copy from the current
|
|
// storage and for the new elements, set the event handle.
|
|
// ============================================================
|
|
|
|
int iCnt ;
|
|
for ( iCnt = 0 ; (DWORD)iCnt < dwAllocSize ; iCnt ++ )
|
|
{
|
|
if ( (DWORD) iCnt < m_RequestContainerSize )
|
|
{
|
|
pNewRequests [ iCnt ] = m_RequestContainer [ iCnt ] ; // structure copy
|
|
}
|
|
else
|
|
{
|
|
pNewRequests [ iCnt ].m_Event = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
|
|
if ( pNewRequests [ iCnt ].m_Event )
|
|
{
|
|
// Got at least one event handle. If it is the first and
|
|
// if the caller is interested, set the pointer to this
|
|
// slot entry.
|
|
// ======================================================
|
|
|
|
if ( ! bOK )
|
|
{
|
|
piAvailable = iCnt ;
|
|
}
|
|
|
|
bOK = TRUE ; // Added at least one!
|
|
}
|
|
|
|
pNewRequests [ iCnt ].m_InUse = FALSE ;
|
|
}
|
|
}
|
|
|
|
if ( ! bOK )
|
|
{
|
|
delete [] pNewRequests ;
|
|
}
|
|
else
|
|
{
|
|
if ( m_RequestContainer )
|
|
{
|
|
delete [] m_RequestContainer ;
|
|
}
|
|
|
|
m_RequestContainer = pNewRequests ;
|
|
m_RequestContainerSize = dwAllocSize ;
|
|
}
|
|
|
|
return bOK ;
|
|
}
|
|
|
|
|